summaryrefslogtreecommitdiffstats
path: root/source3/script
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
commit8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch)
tree4099e8021376c7d8c05bdf8503093d80e9c7bad0 /source3/script
parentInitial commit. (diff)
downloadsamba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz
samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source3/script')
-rwxr-xr-xsource3/script/count_80_col.pl16
-rwxr-xr-xsource3/script/creategroup25
-rwxr-xr-xsource3/script/fix_bool.pl19
-rwxr-xr-xsource3/script/format_indent.sh12
-rw-r--r--source3/script/makeunicodecasemap.awk59
-rwxr-xr-xsource3/script/mknissmbpasswd.sh28
-rwxr-xr-xsource3/script/mknissmbpwdtbl.sh41
-rwxr-xr-xsource3/script/mksmbpasswd.sh6
-rw-r--r--source3/script/mksyms.awk76
-rwxr-xr-xsource3/script/mksyms.sh46
-rwxr-xr-xsource3/script/samba-log-parser382
-rwxr-xr-xsource3/script/scancvslog.pl112
-rwxr-xr-xsource3/script/smbaddshare32
-rwxr-xr-xsource3/script/smbchangeshare47
-rwxr-xr-xsource3/script/smbdeleteshare21
-rw-r--r--source3/script/smbtar181
-rwxr-xr-xsource3/script/strip_trail_ws.pl18
-rwxr-xr-xsource3/script/tests/dlopen.sh90
-rwxr-xr-xsource3/script/tests/fake_snap.pl85
-rwxr-xr-xsource3/script/tests/full_audit_segfault/run.sh25
-rw-r--r--source3/script/tests/full_audit_segfault/vfstest.cmd3
-rwxr-xr-xsource3/script/tests/getset_quota.py154
-rwxr-xr-xsource3/script/tests/printing/modprinter.pl140
-rwxr-xr-xsource3/script/tests/printing/printing_var_exp_lpr_cmd.sh9
-rw-r--r--source3/script/tests/smbspool_argv_wrapper.c72
-rwxr-xr-xsource3/script/tests/stream-depot/run.sh36
-rw-r--r--source3/script/tests/stream-depot/vfstest.cmd5
-rwxr-xr-xsource3/script/tests/test_acl_xattr.sh156
-rwxr-xr-xsource3/script/tests/test_aio_outstanding.sh99
-rwxr-xr-xsource3/script/tests/test_async_req.sh14
-rwxr-xr-xsource3/script/tests/test_bad_auditnames.sh29
-rwxr-xr-xsource3/script/tests/test_bug15435_widelink_dfs.sh28
-rwxr-xr-xsource3/script/tests/test_chdir_cache.sh122
-rwxr-xr-xsource3/script/tests/test_close_denied_share.sh78
-rwxr-xr-xsource3/script/tests/test_deadtime.sh67
-rwxr-xr-xsource3/script/tests/test_delete_stream.sh123
-rwxr-xr-xsource3/script/tests/test_delete_veto_files_only_rmdir.sh182
-rwxr-xr-xsource3/script/tests/test_dfree_command.sh69
-rwxr-xr-xsource3/script/tests/test_dfree_quota.sh296
-rwxr-xr-xsource3/script/tests/test_dropbox.sh88
-rwxr-xr-xsource3/script/tests/test_durable_handle_reconnect.sh36
-rwxr-xr-xsource3/script/tests/test_failure.sh34
-rwxr-xr-xsource3/script/tests/test_fakedircreatetimes.sh65
-rwxr-xr-xsource3/script/tests/test_fifo.sh83
-rwxr-xr-xsource3/script/tests/test_force_close_share.sh115
-rwxr-xr-xsource3/script/tests/test_force_create_mode.sh72
-rwxr-xr-xsource3/script/tests/test_force_group_change.sh73
-rwxr-xr-xsource3/script/tests/test_force_user_unlink.sh41
-rwxr-xr-xsource3/script/tests/test_forceuser_validusers.sh60
-rwxr-xr-xsource3/script/tests/test_fruit_resource_stream.sh41
-rwxr-xr-xsource3/script/tests/test_give_owner.sh147
-rwxr-xr-xsource3/script/tests/test_groupmap.sh217
-rwxr-xr-xsource3/script/tests/test_guest_auth.sh106
-rwxr-xr-xsource3/script/tests/test_homes.sh136
-rwxr-xr-xsource3/script/tests/test_inherit_owner.sh170
-rwxr-xr-xsource3/script/tests/test_large_acl.sh61
-rwxr-xr-xsource3/script/tests/test_libwbclient_threads.sh17
-rwxr-xr-xsource3/script/tests/test_list_nt4_trust.sh25
-rwxr-xr-xsource3/script/tests/test_local_s3.sh39
-rwxr-xr-xsource3/script/tests/test_net_cache_samlogon.sh43
-rwxr-xr-xsource3/script/tests/test_net_conf.sh1042
-rwxr-xr-xsource3/script/tests/test_net_cred_change.sh17
-rwxr-xr-xsource3/script/tests/test_net_cred_change_at.sh33
-rwxr-xr-xsource3/script/tests/test_net_dom_join_fail_dc.sh22
-rwxr-xr-xsource3/script/tests/test_net_lookup.sh54
-rwxr-xr-xsource3/script/tests/test_net_machine_account.sh34
-rwxr-xr-xsource3/script/tests/test_net_misc.sh80
-rwxr-xr-xsource3/script/tests/test_net_registry.sh411
-rwxr-xr-xsource3/script/tests/test_net_registry_check.sh145
-rwxr-xr-xsource3/script/tests/test_net_registry_import.sh192
-rwxr-xr-xsource3/script/tests/test_net_registry_roundtrip.sh158
-rwxr-xr-xsource3/script/tests/test_net_rpc_join.sh25
-rwxr-xr-xsource3/script/tests/test_net_rpc_join_creds.sh30
-rwxr-xr-xsource3/script/tests/test_net_rpc_oldjoin.sh49
-rwxr-xr-xsource3/script/tests/test_net_rpc_share_allowedusers.sh49
-rwxr-xr-xsource3/script/tests/test_net_tdb.sh104
-rwxr-xr-xsource3/script/tests/test_net_usershare.sh83
-rwxr-xr-xsource3/script/tests/test_netfileenum.sh84
-rwxr-xr-xsource3/script/tests/test_nt4_trust.sh31
-rwxr-xr-xsource3/script/tests/test_offline.sh33
-rwxr-xr-xsource3/script/tests/test_old_dirlisting.sh28
-rwxr-xr-xsource3/script/tests/test_open_eintr.sh77
-rwxr-xr-xsource3/script/tests/test_preserve_case.sh86
-rwxr-xr-xsource3/script/tests/test_printing_var_exp.sh93
-rwxr-xr-xsource3/script/tests/test_pthreadpool.sh20
-rwxr-xr-xsource3/script/tests/test_recycle.sh102
-rwxr-xr-xsource3/script/tests/test_registry_share.sh39
-rwxr-xr-xsource3/script/tests/test_registry_upgrade.sh192
-rwxr-xr-xsource3/script/tests/test_resolvconf.sh20
-rwxr-xr-xsource3/script/tests/test_rofs.sh34
-rwxr-xr-xsource3/script/tests/test_rpcclient.sh19
-rwxr-xr-xsource3/script/tests/test_rpcclient_dfs.sh45
-rwxr-xr-xsource3/script/tests/test_rpcclient_lookup.sh42
-rwxr-xr-xsource3/script/tests/test_rpcclient_netsessenum.sh55
-rwxr-xr-xsource3/script/tests/test_rpcclient_pw_nt_hash.sh27
-rwxr-xr-xsource3/script/tests/test_rpcclient_samlogon.sh32
-rwxr-xr-xsource3/script/tests/test_rpcclientsrvsvc.sh90
-rwxr-xr-xsource3/script/tests/test_sacl_set_get.sh45
-rwxr-xr-xsource3/script/tests/test_server_addresses.sh32
-rwxr-xr-xsource3/script/tests/test_shadow_copy.sh458
-rwxr-xr-xsource3/script/tests/test_shadow_copy_torture.sh227
-rwxr-xr-xsource3/script/tests/test_shareenum.sh31
-rwxr-xr-xsource3/script/tests/test_sharesec.sh140
-rwxr-xr-xsource3/script/tests/test_smb1_shadow_copy_torture.sh77
-rwxr-xr-xsource3/script/tests/test_smb1_system_security.sh44
-rwxr-xr-xsource3/script/tests/test_smb2_not_casesensitive.sh81
-rwxr-xr-xsource3/script/tests/test_smbXsrv_client_cross_node.sh92
-rwxr-xr-xsource3/script/tests/test_smbXsrv_client_ctdb_registered_ips.sh159
-rwxr-xr-xsource3/script/tests/test_smbXsrv_client_dead_rec.sh76
-rwxr-xr-xsource3/script/tests/test_smbclient_auth.sh47
-rwxr-xr-xsource3/script/tests/test_smbclient_basic.sh47
-rwxr-xr-xsource3/script/tests/test_smbclient_encryption.sh72
-rwxr-xr-xsource3/script/tests/test_smbclient_encryption_off.sh65
-rwxr-xr-xsource3/script/tests/test_smbclient_iconv.sh55
-rwxr-xr-xsource3/script/tests/test_smbclient_kerberos.sh80
-rwxr-xr-xsource3/script/tests/test_smbclient_krb5.sh21
-rwxr-xr-xsource3/script/tests/test_smbclient_large_file.sh62
-rwxr-xr-xsource3/script/tests/test_smbclient_list_servers.sh45
-rwxr-xr-xsource3/script/tests/test_smbclient_log_basename.sh36
-rwxr-xr-xsource3/script/tests/test_smbclient_machine_auth.sh44
-rwxr-xr-xsource3/script/tests/test_smbclient_mget.sh47
-rwxr-xr-xsource3/script/tests/test_smbclient_netbios_aliases.sh42
-rwxr-xr-xsource3/script/tests/test_smbclient_ntlm.sh80
-rwxr-xr-xsource3/script/tests/test_smbclient_s3.sh2364
-rwxr-xr-xsource3/script/tests/test_smbclient_tarmode.pl1723
-rwxr-xr-xsource3/script/tests/test_smbclient_tarmode.sh197
-rwxr-xr-xsource3/script/tests/test_smbcquota.py244
-rwxr-xr-xsource3/script/tests/test_smbcquota.sh45
-rwxr-xr-xsource3/script/tests/test_smbd_error.sh66
-rwxr-xr-xsource3/script/tests/test_smbd_no_krb5.sh46
-rwxr-xr-xsource3/script/tests/test_smbget.sh619
-rwxr-xr-xsource3/script/tests/test_smbpasswd.sh133
-rwxr-xr-xsource3/script/tests/test_smbspool.sh294
-rwxr-xr-xsource3/script/tests/test_smbspool_krb.sh90
-rwxr-xr-xsource3/script/tests/test_smbstatus.sh479
-rwxr-xr-xsource3/script/tests/test_smbtorture_nocrash_s3.sh38
-rwxr-xr-xsource3/script/tests/test_smbtorture_s3.sh26
-rwxr-xr-xsource3/script/tests/test_stream_dir_rename.sh72
-rwxr-xr-xsource3/script/tests/test_substitutions.sh79
-rwxr-xr-xsource3/script/tests/test_success.sh21
-rwxr-xr-xsource3/script/tests/test_symlink_dosmode.sh74
-rwxr-xr-xsource3/script/tests/test_symlink_rename_smb1_posix.sh185
-rwxr-xr-xsource3/script/tests/test_symlink_traversal_smb1.sh262
-rwxr-xr-xsource3/script/tests/test_symlink_traversal_smb1_posix.sh269
-rwxr-xr-xsource3/script/tests/test_symlink_traversal_smb2.sh382
-rwxr-xr-xsource3/script/tests/test_testparm_s3.sh150
-rwxr-xr-xsource3/script/tests/test_tevent_glib_glue.sh20
-rwxr-xr-xsource3/script/tests/test_timestamps.sh72
-rwxr-xr-xsource3/script/tests/test_user_in_sharelist.sh22
-rwxr-xr-xsource3/script/tests/test_usernamemap.sh28
-rwxr-xr-xsource3/script/tests/test_valid_users.sh70
-rwxr-xr-xsource3/script/tests/test_veto_files.sh279
-rwxr-xr-xsource3/script/tests/test_veto_rmdir.sh217
-rwxr-xr-xsource3/script/tests/test_virus_scanner.sh135
-rwxr-xr-xsource3/script/tests/test_volume_serial_number.sh37
-rwxr-xr-xsource3/script/tests/test_wbinfo_lookuprids_cache.sh31
-rwxr-xr-xsource3/script/tests/test_wbinfo_sids2xids.sh12
-rwxr-xr-xsource3/script/tests/test_wbinfo_sids2xids_int.py147
-rwxr-xr-xsource3/script/tests/test_wbinfo_u_large_ad.sh28
-rwxr-xr-xsource3/script/tests/test_winbind_call_depth_trace.sh113
-rwxr-xr-xsource3/script/tests/test_winbind_ignore_domains.sh106
-rwxr-xr-xsource3/script/tests/test_worm.sh121
-rwxr-xr-xsource3/script/tests/test_zero_data.sh54
-rwxr-xr-xsource3/script/tests/test_zero_readsize.sh101
-rw-r--r--source3/script/tests/timelimit.c102
-rwxr-xr-xsource3/script/tests/vfstest-acl/run.sh52
-rw-r--r--source3/script/tests/vfstest-acl/vfstest.cmd15
-rwxr-xr-xsource3/script/tests/vfstest-catia/run.sh102
-rw-r--r--source3/script/tests/vfstest-catia/vfstest.cmd2
-rw-r--r--source3/script/tests/vfstest-catia/vfstest1.cmd2
-rwxr-xr-xsource3/script/tests/wb_pad.sh83
-rwxr-xr-xsource3/script/tests/xattr-tdb-1/run.sh52
-rw-r--r--source3/script/tests/xattr-tdb-1/vfstest.cmd6
-rwxr-xr-xsource3/script/updatesmbpasswd.sh14
-rw-r--r--source3/script/wscript_build13
175 files changed, 20448 insertions, 0 deletions
diff --git a/source3/script/count_80_col.pl b/source3/script/count_80_col.pl
new file mode 100755
index 0000000..8b22622
--- /dev/null
+++ b/source3/script/count_80_col.pl
@@ -0,0 +1,16 @@
+#!/usr/bin/perl -w
+
+open( INFILE, "$ARGV[0]" ) || die $@;
+
+$count = 0;
+while ( <INFILE> ) {
+ next if ($_ =~ /^#define/);
+ $count++ if (length($_) > 80);
+}
+
+close( INFILE );
+print "$ARGV[0]: $count lines > 80 characters\n" if ($count > 0);
+
+exit( 0 );
+
+
diff --git a/source3/script/creategroup b/source3/script/creategroup
new file mode 100755
index 0000000..1e24867
--- /dev/null
+++ b/source3/script/creategroup
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# Example script for 'add group command'. Handle weird NT group
+# names. First attempt to create the group directly, if that fails
+# then create a random group and print the numeric group id.
+#
+# Note that this is only an example and assumes /dev/urandom.
+#
+# Volker
+
+GROUPNAME="$1"
+ITERS=0
+
+while ! /usr/sbin/groupadd "$GROUPNAME" >/dev/null 2>&1; do
+ # we had difficulties creating that group. Maybe the name was
+ # too weird, or it already existed. Create a random name.
+ GROUPNAME=nt-$(dd if=/dev/urandom bs=16 count=1 2>/dev/null | md5sum | cut -b 1-5)
+ ITERS=$(expr "$ITERS" + 1)
+ if [ "$ITERS" -gt 10 ]; then
+ # Too many attempts
+ exit 1
+ fi
+done
+
+getent group | grep ^"$GROUPNAME": | cut -d : -f 3
diff --git a/source3/script/fix_bool.pl b/source3/script/fix_bool.pl
new file mode 100755
index 0000000..c09645d
--- /dev/null
+++ b/source3/script/fix_bool.pl
@@ -0,0 +1,19 @@
+#!/usr/bin/perl -w
+
+open(INFILE, "$ARGV[0]") || die $@;
+open(OUTFILE, ">$ARGV[0].new") || die $@;
+
+while (<INFILE>) {
+ $_ =~ s/True/true/;
+ $_ =~ s/False/false/;
+ print OUTFILE "$_";
+}
+
+close(INFILE);
+close(OUTFILE);
+
+rename("$ARGV[0].new", "$ARGV[0]") || die @_;
+
+exit(0);
+
+
diff --git a/source3/script/format_indent.sh b/source3/script/format_indent.sh
new file mode 100755
index 0000000..11ef285
--- /dev/null
+++ b/source3/script/format_indent.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# -npro Do no read the '.indent.pro' files.
+# -kr Use K&R formatting rules
+# -i8 Set indentation level to 8 spaces.
+# -ts8 Set tab size to 8 spaces
+# -sob Swallow optional blank lines.
+# -l80 Set the maximum line length at 80 characters.
+# -ss On one-line for and while statements, force a blank before the semicolon
+# -ncs Do not put a space after cast operators.
+
+indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs "$@"
diff --git a/source3/script/makeunicodecasemap.awk b/source3/script/makeunicodecasemap.awk
new file mode 100644
index 0000000..8424b6c
--- /dev/null
+++ b/source3/script/makeunicodecasemap.awk
@@ -0,0 +1,59 @@
+function reset_vals() {
+ upperstr = "";
+ lowerstr = "";
+ flagstr = "0";
+}
+
+function print_val() {
+ upperstr = $13;
+ lowerstr = $14;
+ if ( upperstr == "" )
+ upperstr = strval;
+ if ( lowerstr == "" )
+ lowerstr = strval;
+
+ if ( $3 == "Lu" )
+ flagstr = sprintf("%s|%s", flagstr, "UNI_UPPER");
+ if ( $3 == "Ll" )
+ flagstr = sprintf("%s|%s", flagstr, "UNI_LOWER");
+ if ( val >= 48 && val <= 57)
+ flagstr = sprintf("%s|%s", flagstr, "UNI_DIGIT");
+ if ((val >= 48 && val <= 57) || (val >= 65 && val <= 70) || (val >=97 && val <= 102))
+ flagstr = sprintf("%s|%s", flagstr, "UNI_XDIGIT");
+ if ( val == 32 || (val >=9 && val <= 13))
+ flagstr = sprintf("%s|%s", flagstr, "UNI_SPACE");
+ if( index(flagstr, "0|") == 1)
+ flagstr = substr(flagstr, 3, length(flagstr) - 2);
+ printf("{ 0x%s, 0x%s, %s }, \t\t\t/* %s %s */\n", lowerstr, upperstr, flagstr, strval, $2);
+ val++;
+ strval=sprintf("%04X", val);
+ reset_vals();
+}
+
+BEGIN {
+ val=0
+ FS=";"
+ strval=sprintf("%04X", val);
+ reset_vals();
+}
+
+{
+ if ( $1 == strval ) {
+ print_val();
+ } else {
+ while ( $1 != strval) {
+ printf("{ 0x%04X, 0x%04X, 0 }, \t\t\t/* %s NOMAP */\n", val, val, strval);
+ val++;
+ strval=sprintf("%04X", val);
+ }
+ print_val();
+ }
+}
+
+END {
+ while ( val < 65536 ) {
+ printf("{ 0x%04X, 0x%04X, 0 }, \t\t\t/* %s NOMAP */\n", val, val, strval);
+ val++;
+ strval=sprintf("%04X", val);
+ }
+}
diff --git a/source3/script/mknissmbpasswd.sh b/source3/script/mknissmbpasswd.sh
new file mode 100755
index 0000000..2fea32c
--- /dev/null
+++ b/source3/script/mknissmbpasswd.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# Copyright (C) 1998 Benny Holmgren
+#
+# Script to import smbpasswd file into the smbpasswd NIS+ table. Reads
+# from stdin the smbpasswd file.
+#
+while true; do
+ read row
+ if [ -z "$row" ]; then
+ break
+ fi
+
+ if [ "$(echo $row | cut -c1)" = "#" ]; then
+ continue
+ fi
+
+ nistbladm -a \
+ name=\"$(echo $row | cut -d: -f1)\" \
+ uid=\"$(echo $row | cut -d: -f2)\" \
+ lmpwd=\"$(echo $row | cut -d: -f3)\" \
+ ntpwd=\"$(echo $row | cut -d: -f4)\" \
+ acb=\"$(echo $row | cut -d: -f5)\" \
+ pwdlset_t=\"$(echo $row | cut -d: -f6)\" \
+ gcos=\"$(echo $row | cut -d: -f7)\" \
+ home=\"$(echo $row | cut -d: -f8)\" \
+ shell=\"$(echo $row | cut -d: -f9)\" smbpasswd.org_dir.$(nisdefaults -d)
+done
diff --git a/source3/script/mknissmbpwdtbl.sh b/source3/script/mknissmbpwdtbl.sh
new file mode 100755
index 0000000..d7291bb
--- /dev/null
+++ b/source3/script/mknissmbpwdtbl.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# Copyright (C) 1998 Benny Holmgren
+#
+# Creates smbpasswd table and smb group in NIS+
+#
+
+nistbladm \
+ -D access=og=rmcd,nw= -c \
+ -s : smbpasswd_tbl \
+ name=S,nogw=r \
+ uid=S,nogw=r \
+ user_rid=S,nogw=r \
+ smb_grpid=,nw+r \
+ group_rid=,nw+r \
+ acb=,nw+r \
+ \
+ lmpwd=C,nw=,g=r,o=rm \
+ ntpwd=C,nw=,g=r,o=rm \
+ \
+ logon_t=,nw+r \
+ logoff_t=,nw+r \
+ kick_t=,nw+r \
+ pwdlset_t=,nw+r \
+ pwdlchg_t=,nw+r \
+ pwdmchg_t=,nw+r \
+ \
+ full_name=,nw+r \
+ home_dir=,nw+r \
+ dir_drive=,nw+r \
+ logon_script=,nw+r \
+ profile_path=,nw+r \
+ acct_desc=,nw+r \
+ workstations=,nw+r \
+ \
+ hours=,nw+r \
+ smbpasswd.org_dir.$(nisdefaults -d)
+
+nisgrpadm -c smb.$(nisdefaults -d)
+
+nischgrp smb.$(nisdefaults -d) smbpasswd.org_dir.$(nisdefaults -d)
diff --git a/source3/script/mksmbpasswd.sh b/source3/script/mksmbpasswd.sh
new file mode 100755
index 0000000..119a556
--- /dev/null
+++ b/source3/script/mksmbpasswd.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+awk 'BEGIN {FS=":"
+ printf("#\n# SMB password file.\n#\n")
+ }
+{ printf( "%s:%s:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:[UD ]:LCT-00000000:%s\n", $1, $3, $5) }
+'
diff --git a/source3/script/mksyms.awk b/source3/script/mksyms.awk
new file mode 100644
index 0000000..94a405c
--- /dev/null
+++ b/source3/script/mksyms.awk
@@ -0,0 +1,76 @@
+#
+# mksyms.awk
+#
+# Extract symbols to export from C-header files.
+# output in version-script format for linking shared libraries.
+#
+# Copyright (C) 2008 Michael Adam <obnox@samba.org>
+#
+BEGIN {
+ inheader=0;
+ current_file="";
+ print "#"
+ print "# This file is automatically generated with \"make symbols\". DO NOT EDIT "
+ print "#"
+ print "{"
+ print "\tglobal:"
+}
+
+END {
+ print""
+ print "\tlocal: *;"
+ print "};"
+}
+
+{
+ if (FILENAME!=current_file) {
+ print "\t\t# The following definitions come from",FILENAME
+ current_file=FILENAME
+ }
+ if (inheader) {
+ if (match($0,"[)][^()]*[;][ \t]*$")) {
+ inheader = 0;
+ }
+ next;
+ }
+}
+
+/^static/ || /^[ \t]*typedef/ || !/^[a-zA-Z\_]/ {
+ next;
+}
+
+/^extern[ \t]+[^()]+[;][ \t]*$/ {
+ gsub(/[^ \t]+[ \t]+/, "");
+ sub(/[;][ \t]*$/, "");
+ printf "\t\t%s;\n", $0;
+ next;
+}
+
+# look for function headers:
+{
+ gotstart = 0;
+ if ($0 ~ /^[A-Za-z_][A-Za-z0-9_]+/) {
+ gotstart = 1;
+ }
+ if(!gotstart) {
+ next;
+ }
+}
+
+/[_A-Za-z0-9]+[ \t]*[(].*[)][^()]*;[ \t]*$/ {
+ sub(/[(].*$/, "");
+ gsub(/[^ \t]+[ \t]+/, "");
+ gsub(/^[*]+/, "");
+ printf "\t\t%s;\n",$0;
+ next;
+}
+
+/[_A-Za-z0-9]+[ \t]*[(]/ {
+ inheader=1;
+ sub(/[(].*$/, "");
+ gsub(/[^ \t]+[ \t]+/, "");
+ gsub(/^[*]/, "");
+ printf "\t\t%s;\n",$0;
+ next;
+}
+
diff --git a/source3/script/mksyms.sh b/source3/script/mksyms.sh
new file mode 100755
index 0000000..9a08685
--- /dev/null
+++ b/source3/script/mksyms.sh
@@ -0,0 +1,46 @@
+#! /bin/sh
+
+#
+# mksyms.sh
+#
+# Extract symbols to export from C-header files.
+# output in version-script format for linking shared libraries.
+#
+# This is the shell wrapper for the mksyms.awk core script.
+#
+# Copyright (C) 2008 Michael Adam <obnox@samba.org>
+#
+
+LANG=C
+export LANG
+LC_ALL=C
+export LC_ALL
+LC_COLLATE=C
+export LC_COLLATE
+
+if [ $# -lt 2 ]; then
+ echo "Usage: $0 awk output_file header_files"
+ exit 1
+fi
+
+awk="$1"
+shift
+
+symsfile="$1"
+shift
+symsfile_tmp="$symsfile.$$.tmp~"
+
+proto_src="$(echo "$@" | tr ' ' '\n' | sort | uniq)"
+
+echo creating $symsfile
+
+mkdir -p $(dirname $symsfile)
+
+${awk} -f $(dirname $0)/mksyms.awk $proto_src >$symsfile_tmp
+
+if cmp -s $symsfile $symsfile_tmp 2>/dev/null; then
+ echo "$symsfile unchanged"
+ rm $symsfile_tmp
+else
+ mv $symsfile_tmp $symsfile
+fi
diff --git a/source3/script/samba-log-parser b/source3/script/samba-log-parser
new file mode 100755
index 0000000..a07dfdb
--- /dev/null
+++ b/source3/script/samba-log-parser
@@ -0,0 +1,382 @@
+#!/usr/bin/env python3
+#
+#######################################################################
+#
+# A script to parse samba (especially winbind) logfiles.
+# Trace files should be in a non-syslog format (debug syslog format = no).
+#
+# --traceid ... Specify the traceid of the request to parse
+# --pid ... Specify the pid
+# --breakdown ... Break to separate files per each traceid
+# --merge-by-timestamp ... Merge logs by timestamp
+# --flow ... Show the request/sub-request call flow
+# --flow-compact ... Show the request/sub-request call flow without dcerpc
+#
+#
+# Copyright (c) 2023 Andreas Schneider <asn@samba.org>
+# Copyright (c) 2023 Pavel Filipenský <pfilipen@redhat.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#######################################################################
+#
+# Requires: ???
+
+import sys
+import os
+import re
+from argparse import ArgumentParser
+from collections import defaultdict
+
+# Trace record consists of a trace header followed by one or more text lines.
+#
+# This tool expects trace header format based on these smb.conf parameters:
+#
+# debug syslog format = no
+# debug hires timestamp = yes
+# winbind debug traceid = yes
+#
+# If 'winbind debug traceid = no' is set, then the option --merge-by-timestamp
+# still can be used.
+#
+# Each trace header contains a traceid, which is the main identifier for this
+# tool. A single traceid is either provided via command line option --traceid
+# or a list of traceids is derived from the PID specified via option --pid.
+# Creating and evaluating list of traceids from PID can be tricky:
+# The traceid can appear in a trace record before trace record containing the
+# PID is processed. So when we see a new traceid we are not sure if it belongs
+# to the traced PID.
+# The PID appears only in the main winbind process (log.winbind). If a
+# directory with many log files should be processed, we process the files in
+# random order.
+# It might happen that e.g. log.wb-ADDOMAIN is processed before log.winbind so
+# we do not know the list of traceids yet.
+# To make all this easy we put into memory all trace records and do the final
+# traceid filtering only after all files are read. This can require lot of
+# memory if files are big.
+
+
+def process_file_no_traceid(record_list, fname):
+ with open(fname, "r") as infile:
+ data = infile.readlines()
+ date = ""
+ record_lines = []
+
+ RE_HEADER_NO_TRACEID = re.compile(
+ r"^\[(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}\.\d{6}).*")
+ for line in data:
+ header = RE_HEADER_NO_TRACEID.search(line)
+ if header:
+ # Append all previous trace lines of a record
+ if record_lines:
+ record_list.append((date, None, record_lines, fname))
+ record_lines = []
+ # Remember the new date
+ date = header.group(1)
+ record_lines.append(line)
+
+
+def process_file(record_list, traceid_set, fname, opid, otraceid):
+ with open(fname, "r") as infile:
+ data = infile.readlines()
+ pid = None
+ traceid = 0
+ traceid_prev = None
+ undecided_traceid = False
+ date = ""
+ record_lines = []
+
+ # If traceid option was provided the traceid_set will contain just it
+ if otraceid:
+ traceid_set.add(otraceid)
+
+ RE_HEADER = re.compile(
+ r"^\[(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}\.\d{6}).*?, .*, "
+ r"traceid=([0-9]+).*\]")
+ RE_INTERFACE_VERSION = re.compile(
+ r"^\s+winbindd_interface_version: \[\S* \((\d+)\)\]")
+ RE_ASYNC_REQUEST = re.compile(
+ r"^\s+process_request_send: "
+ r"\[\S* \((\d+)\)\] Handling async request:")
+ # Example of a header line
+ # [2023/05/01 07:40:45.439049, 3, pid=418844, effective(0, 0), real(0, 0), class=winbind, traceid=37] ../../source3/winbindd/winbindd_misc.c:355(winbindd_interface_version)
+ for line in data:
+ header = RE_HEADER.search(line)
+ if header:
+ # Append all previous trace lines of a record if the traceid is in
+ # the list.
+ if record_lines:
+ record_list.append((date, traceid, record_lines, fname))
+ record_lines = []
+ # Remember the new date and the new traceid
+ date = header.group(1)
+ traceid = header.group(2)
+ if traceid != traceid_prev:
+ traceid_prev = traceid
+ undecided_traceid = True
+ if opid:
+ # Search for lines that identify a new winbind client and the
+ # client PID
+
+ # winbindd_interface_version: [nss_winbind (500725)]: request interface version (version = 32)
+ # process_request_send: [nss_winbind (500725)] Handling async request: SETPWENT
+ interface_version = RE_INTERFACE_VERSION.search(line)
+ async_request = RE_ASYNC_REQUEST.search(line)
+ if interface_version:
+ pid = interface_version.group(1)
+ if undecided_traceid:
+ if pid == opid:
+ traceid_set.add(traceid)
+ undecided_traceid = False
+ if async_request:
+ pid = async_request.group(1)
+ if undecided_traceid:
+ if pid == opid:
+ traceid_set.add(traceid)
+ undecided_traceid = False
+ # For --breakdown add every traceid
+ if not opid and not otraceid:
+ traceid_set.add(traceid)
+
+ record_lines.append(line)
+
+
+def filter_traceids(record_list, traceid_set):
+ llist = []
+ for (d, t, li, f) in record_list:
+ if t in traceid_set:
+ llist.append((d, t, li, f))
+ return llist
+
+
+def filter_flow(record_list):
+ local_list = []
+ for (date, traceid, lines, filename) in record_list:
+ for line in lines:
+ isflow = re.search(r"^(\s+)flow: (.*)", line)
+ if isflow:
+ local_list.append(isflow.group(1) + isflow.group(2))
+ return local_list
+
+
+def filter_flowcompact(flist):
+ local_list = []
+ end_marker = None
+ for fl in flist:
+ if not end_marker:
+ local_list.append(fl)
+ dcerpc_start = re.search(r"^(\s+)-> dcerpc_", fl)
+ if dcerpc_start:
+ end_marker = dcerpc_start.group(1)
+ else:
+ dcerpc_end = re.search(r"^" + end_marker + "<- dcerpc_", fl)
+ if dcerpc_end:
+ end_marker = None
+ local_list.append(fl)
+ return local_list
+
+
+def print_record_list(record_list, file):
+ f_prev = None
+ for (date, traceid, lines, filename) in record_list:
+ # Inform about filename change
+ if filename != f_prev:
+ print("-" * 72, file=file)
+ print("FILE: ", filename, file=file)
+ print("-" * 72, file=file)
+ for line in lines:
+ print(line, end='', file=file)
+ f_prev = filename
+
+# record_list ... list of quadruplets <date, traceid, [trace lines], filename>
+# flow_list ... lines from record_list with 'flow' traces
+# traceid_set ... list of traceids we want to trace
+# with --traceid ... there is a single traceids
+# with --pid ... there are all traceids for the PID
+# with --breakdown ... there are all traceids
+
+
+def setup_parser():
+ parser = ArgumentParser()
+
+ parser.add_argument(
+ "path",
+ type=str,
+ help="logfile or directory"
+ )
+ parser.add_argument(
+ "--traceid",
+ dest="traceid",
+ help="specify the traceid of the trace records",
+ metavar="ID"
+ )
+ parser.add_argument(
+ "--pid",
+ dest="pid",
+ help="specify the pid of winbind client",
+ metavar="PID"
+ )
+ parser.add_argument(
+ "--breakdown",
+ action="store_true",
+ dest="breakdown",
+ default=False,
+ help="breakdown the traces into per traceid files"
+ )
+ parser.add_argument(
+ "--merge-by-timestamp",
+ action="store_true",
+ dest="merge",
+ default=False,
+ help="merge logs by timestamp"
+ )
+ parser.add_argument(
+ "--flow",
+ action="store_true",
+ dest="flow",
+ default=False,
+ help="show the request/sub-request flow traces"
+ )
+ parser.add_argument(
+ "--flow-compact",
+ action="store_true",
+ dest="flowcompact",
+ default=False,
+ help="show the request/sub-request flow traces without dcerpc details"
+ )
+ return parser
+
+
+def main(): # noqa
+ record_list = []
+ flow_list = []
+ traceid_set = set()
+
+ parser = setup_parser()
+ options = parser.parse_args()
+
+ if (not options.traceid and not options.pid and not options.breakdown
+ and not options.merge):
+ print("One of --traceid or --pid is needed"
+ " or --breakdown or --merge-by-timestamp.")
+ sys.exit(1)
+ elif options.traceid and options.pid:
+ print("Only one of --traceid or --pid is allowed.")
+ sys.exit(1)
+ elif options.breakdown and (options.traceid or options.pid):
+ print("--breakdown cannot be combined with --traceid and --pid.")
+ sys.exit(1)
+
+ if options.flow and not options.traceid:
+ print("Option --flow can be used only together with --traceid.")
+ sys.exit(1)
+
+ if options.flowcompact and not options.traceid:
+ print("Option --flow-compact can be used only together with "
+ "--traceid.")
+ sys.exit(1)
+
+ if options.flow and options.flowcompact:
+ print("Only one of --flow or --flow-compact is allowed.")
+ sys.exit(1)
+
+ if not options.path:
+ print("Path to logfile or directory with logs is needed.")
+ sys.exit(1)
+
+ merge_with_no_traceid = (not options.traceid and not options.pid
+ and not options.breakdown) and options.merge
+
+ path = options.path
+ if os.path.isdir(path):
+ for root, dirs, files in os.walk(path):
+ for name in files:
+ if merge_with_no_traceid:
+ process_file_no_traceid(
+ record_list,
+ os.path.join(root, name)
+ )
+ else:
+ process_file(
+ record_list,
+ traceid_set,
+ os.path.join(root, name),
+ options.pid,
+ options.traceid,
+ )
+ elif os.path.isfile(path):
+ if merge_with_no_traceid:
+ process_file_no_traceid(
+ record_list,
+ path
+ )
+ else:
+ process_file(
+ record_list,
+ traceid_set,
+ path,
+ options.pid,
+ options.traceid
+ )
+ else:
+ print(path, "Path is neither file or directory.")
+ sys.exit(1)
+
+ # Sort only using timestamps, no use of traceid
+ if merge_with_no_traceid:
+ record_list.sort()
+ print_record_list(record_list, sys.stdout)
+ sys.exit(0)
+
+ # Keep only records with matching traceids
+ if not options.breakdown:
+ record_list = filter_traceids(record_list, traceid_set)
+
+ if options.breakdown:
+ for traceid in traceid_set:
+ # Full
+ with open("%s.full" % traceid, "w") as full_f:
+ full_l = filter_traceids(record_list, {traceid})
+ if options.merge:
+ full_l.sort()
+ print_record_list(full_l, full_f)
+ # Flow
+ with open("%s.flow" % traceid, "w") as flow_f:
+ flow_l = filter_flow(full_l)
+ for fl in flow_l:
+ print(fl, file=flow_f)
+ # Flow compact
+ with open("%s.flowcompact" % traceid, "w") as flowcompact_f:
+ flowcompact_l = filter_flowcompact(flow_l)
+ for fl in flowcompact_l:
+ print(fl, file=flowcompact_f)
+ elif options.flow:
+ flow_list = filter_flow(record_list)
+ for fl in flow_list:
+ print(fl)
+ elif options.flowcompact:
+ flow_list = filter_flow(record_list)
+ flow_list = filter_flowcompact(flow_list)
+ for fl in flow_list:
+ print(fl)
+ else:
+ if options.merge:
+ record_list.sort()
+ print_record_list(record_list, sys.stdout)
+
+ sys.exit(0)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/source3/script/scancvslog.pl b/source3/script/scancvslog.pl
new file mode 100755
index 0000000..c39f911
--- /dev/null
+++ b/source3/script/scancvslog.pl
@@ -0,0 +1,112 @@
+#!/usr/bin/perl
+require"timelocal.pl";
+
+#
+# usage scancvslog.pl logfile starttime tag
+#
+# this will extract all entries from the specified cvs log file
+# that have a date later than or equal to starttime and a tag
+# value of tag. If starttime is not specified, all entries are
+# extracted. If tag is not specified then entries for all
+# branches are extracted. starttime must be specified as
+# "monthname day, year"
+#
+# Example to extract all entries for SAMBA_2_2 branch from the
+# log file named cvs.log
+#
+# scancvslog.pl cvs.log "" SAMBA_2_2
+#
+#
+# To extract all log entries after Jan 10, 1999 (Note month name
+# must be spelled out completely).
+#
+# scancvslog.pl cvs.log "January 10, 1999"
+#
+
+open(INFILE,@ARGV[0]) || die "Unable to open @ARGV[0]\n";
+
+%Monthnum = (
+ "January", 0,
+ "February", 1,
+ "March", 2,
+ "April", 3,
+ "May", 4,
+ "June", 5,
+ "July", 6,
+ "August", 7,
+ "September", 8,
+ "October", 9,
+ "November", 10,
+ "December", 11,
+ "Jan", 0,
+ "Feb", 1,
+ "Mar", 2,
+ "Apr", 3,
+ "May", 4,
+ "Jun", 5,
+ "Jul", 6,
+ "Aug", 7,
+ "Sep", 8,
+ "Oct", 9,
+ "Nov", 10,
+ "Dec", 11
+);
+
+$Starttime = (@ARGV[1]) ? &make_time(@ARGV[1]) : 0;
+$Tagvalue = @ARGV[2];
+
+while (&get_entry) {
+ $_=$Entry[0];
+# get rid of extra white space
+ s/\s+/ /g;
+# get rid of any time string in date
+ s/ \d\d:\d\d:\d\d/,/;
+ s/^Date:\s*\w*\s*(\w*)\s*(\w*),\s*(\w*).*/$1 $2 $3/;
+ $Testtime = &make_time($_);
+ $Testtag = &get_tag;
+ if (($Testtime >= $Starttime) && ($Tagvalue eq $Testtag)) {
+ print join("\n",@Entry),"\n";
+ }
+}
+close(INFILE);
+
+sub make_time {
+ $_ = @_[0];
+ s/,//;
+ ($month, $day, $year) = split(" ",$_);
+ if (($year < 1900)||($day < 1)||($day > 31)||not length($Monthnum{$month})) {
+ print "Bad date format @_[0]\n";
+ print "Date needs to be specified as \"Monthname day, year\"\n";
+ print "eg: \"January 10, 1999\"\n";
+ exit 1;
+ }
+ $year = ($year == 19100) ? 2000 : $year;
+ $month = $Monthnum{$month};
+ $Mytime=&timelocal((0,0,0,$day,$month,$year));
+}
+
+sub get_tag {
+ @Mytag = grep (/Tag:/,@Entry);
+ $_ = @Mytag[0];
+ s/^.*Tag:\s*(\w*).*/$1/;
+ return $_;
+}
+
+sub get_entry {
+ @Entry=();
+ if (not eof(INFILE)) {
+ while (not eof(INFILE)) {
+ $_ = <INFILE>;
+ chomp $_;
+ next if (not ($_));
+ if (/^\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/) {
+ next if ($#Entry == -1);
+ push(Entry,$_);
+ return @Entry;
+ } else {
+ push(Entry,$_);
+ }
+ }
+ }
+ return @Entry;
+}
diff --git a/source3/script/smbaddshare b/source3/script/smbaddshare
new file mode 100755
index 0000000..704c9f4
--- /dev/null
+++ b/source3/script/smbaddshare
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# smbaddshare
+#
+# Copyright (C) 2015 Christof Schmitt
+#
+# Example script that can be used with the 'add share command' config
+# option. This is mainly intended for use in the Samba selftest suite,
+# please review and adapt it before using elsewhere.
+#
+
+CONF="$1"
+SHARENAME="$2"
+SHAREPATH="$3"
+COMMENT="$4"
+MAX_CONN="$5"
+
+NETCONF="$BINDIR/net --configfile=$CONF conf"
+
+$NETCONF addshare "$SHARENAME" "$SHAREPATH" writeable=no guest_ok=no "$COMMENT"
+RC=$?
+if [ $RC -ne 0 ]; then
+ echo Failure during addshare: rc=$RC
+ exit $RC
+fi
+
+$NETCONF setparm "$SHARENAME" 'max connections' "$MAX_CONN"
+RC=$?
+if [ $RC -ne 0 ]; then
+ echo Failure during setparm for max connections: rc=$RC
+ exit $RC
+fi
diff --git a/source3/script/smbchangeshare b/source3/script/smbchangeshare
new file mode 100755
index 0000000..098e968
--- /dev/null
+++ b/source3/script/smbchangeshare
@@ -0,0 +1,47 @@
+#!/bin/sh
+#
+# smbchangeshare
+#
+# Copyright (C) 2015 Christof Schmitt
+#
+# Example script that can be used with the 'change share command'
+# config option. This is mainly intended for use in the Samba selftest
+# suite, please review and adapt it before using elsewhere.
+#
+
+CONF="$1"
+SHARENAME="$2"
+SHAREPATH="$3"
+COMMENT="$4"
+MAX_CONN="$5"
+CSC_POLICY="$6"
+
+NETCONF="$BINDIR/net --configfile=$CONF conf"
+
+$NETCONF setparm "$SHARENAME" 'path' "$SHAREPATH"
+RC=$?
+if [ $RC -ne 0 ]; then
+ echo Failure during setparm for path: rc=$RC
+ exit $RC
+fi
+
+$NETCONF setparm "$SHARENAME" 'comment' "$COMMENT"
+RC=$?
+if [ $RC -ne 0 ]; then
+ echo Failed during setparm for comment: rc=$RC
+ exit $RC
+fi
+
+$NETCONF setparm "$SHARENAME" 'max connections' "$MAX_CONN"
+RC=$?
+if [ $RC -ne 0 ]; then
+ echo Failure during setparm for max connections: rc=$RC
+ exit $RC
+fi
+
+$NETCONF setparm "$SHARENAME" 'csc policy' "$CSC_POLICY"
+RC=$?
+if [ $RC -ne 0 ]; then
+ echo Failure during setparm for csc policy: rc=$RC
+ exit $RC
+fi
diff --git a/source3/script/smbdeleteshare b/source3/script/smbdeleteshare
new file mode 100755
index 0000000..8f70678
--- /dev/null
+++ b/source3/script/smbdeleteshare
@@ -0,0 +1,21 @@
+#!/bin/sh
+#
+# smbdeleteshare
+#
+# Copyright (C) 2015 Christof Schmitt
+#
+# Example script that can be used with the 'delete share command'
+# config option. This is mainly intended for use in the Samba selftest
+# suite, please review and adapt it before using elsewhere.
+#
+
+CONF="$1"
+SHARENAME="$2"
+
+NETCONF="$BINDIR/net --configfile=$CONF conf"
+$NETCONF delshare "$SHARENAME"
+RC=$?
+if [ $RC -ne 0 ]; then
+ echo Failure during delshare command: rc=$RC
+ exit $RC
+fi
diff --git a/source3/script/smbtar b/source3/script/smbtar
new file mode 100644
index 0000000..439d085
--- /dev/null
+++ b/source3/script/smbtar
@@ -0,0 +1,181 @@
+#!/bin/sh
+#
+# smbtar script - front end to smbclient
+#
+# Authors: Martin.Kraemer <Martin.Kraemer@mch.sni.de>
+# and Ricky Poulten (ricky@logcam.co.uk)
+#
+# (May need to change shell to ksh for HPUX or OSF for better getopts)
+#
+# sandy nov 3 '98 added -a flag
+#
+# Richard Sharpe, added -c 'tarmode full' so that we back up all files to
+# fix a bug in clitar when a patch was added to stop system and hidden files
+# being backed up.
+
+case $0 in
+# when called by absolute path, assume smbclient is in the same directory
+/*)
+ SMBCLIENT="$(dirname $0)/smbclient"
+ ;;
+*) # you may need to edit this to show where your smbclient is
+ SMBCLIENT="smbclient" ;;
+esac
+
+# These are the default values. You could fill them in if you know what
+# you're doing, but beware: better not store a plain text password!
+server=""
+service="backup" # Default: a service called "backup"
+password=""
+username=$LOGNAME # Default: same user name as in *nix
+verbose="2>/dev/null" # Default: no echo to stdout
+log="-d 2"
+newer=""
+newerarg=""
+blocksize=""
+blocksizearg=""
+clientargs="-c 'tarmode full'"
+tarcmd="c"
+tarargs=""
+cdcmd="\\"
+tapefile=${TAPE-tar.out}
+
+Usage()
+{
+ ex=$1
+ shift
+ echo >&2 "Usage: $(basename $0) [<options>] [<include/exclude files>]
+Function: backup/restore a Windows PC directories to a local tape file
+Options: (Description) (Default)
+ -r Restore from tape file to PC Save from PC to tapefile
+ -i Incremental mode Full backup mode
+ -a Reset archive bit mode Don't reset archive bit
+ -v Verbose mode: echo command Don't echo anything
+ -s <server> Specify PC Server $server
+ -p <password> Specify PC Password $password
+ -x <share> Specify PC Share $service
+ -X Exclude mode Include
+ -N <newer> File for date comparison $(
+ set -- $newer
+ echo $2
+ )
+ -b <blocksize> Specify tape's blocksize $(
+ set -- $blocksize
+ echo $2
+ )
+ -d <dir> Specify a directory in share $cdcmd
+ -l <log> Specify a Samba Log Level $(
+ set -- $log
+ echo $2
+ )
+ -u <user> Specify User Name $username
+ -t <tape> Specify Tape device $tapefile
+"
+ echo >&2 "$@"
+ exit $ex
+}
+
+# echo Params count: $#
+
+# DEC OSF AKA Digital UNIX does not seem to return a value in OPTIND if
+# there are no command line params, so protect us against that ...
+if [ $# = 0 ]; then
+
+ Usage 2 "Please enter a command line parameter!"
+
+fi
+
+while getopts riavl:b:d:N:s:p:x:u:Xt: c; do
+ case $c in
+ r) # [r]estore to Windows (instead of the default "Save from Windows")
+ tarcmd="x"
+ ;;
+ i) # [i]ncremental
+ tarargs=${tarargs}ga
+ clientargs="-c 'tarmode inc'"
+ ;;
+ a) # [a]rchive
+ tarargs=${tarargs}a
+ ;;
+ l) # specify [l]og file
+ log="-d $OPTARG"
+ case "$OPTARG" in
+ [0-9]*) ;;
+ *)
+ echo >&2 "$0: Error, log level not numeric: -l $OPTARG"
+ exit 1
+ ;;
+ esac
+ ;;
+ d) # specify [d]irectory to change to in server's share
+ cdcmd="$OPTARG"
+ ;;
+ N) # compare with a file, test if [n]ewer
+ if [ -f $OPTARG ]; then
+ newer=$OPTARG
+ newerarg="N"
+ else
+ echo >&2 $0: Warning, $OPTARG not found
+ fi
+ ;;
+ X) # Add exclude flag
+ tarargs=${tarargs}X
+ ;;
+ s) # specify [s]erver's share to connect to - this MUST be given.
+ server="$OPTARG"
+ ;;
+ b) # specify [b]locksize
+ blocksize="$OPTARG"
+ case "$OPTARG" in
+ [0-9]*) ;;
+ *)
+ echo >&2 "$0: Error, block size not numeric: -b $OPTARG"
+ exit 1
+ ;;
+ esac
+ blocksizearg="b"
+ ;;
+ p) # specify [p]assword to use
+ password="$OPTARG"
+ ;;
+ x) # specify windows [s]hare to use
+ service="$OPTARG"
+ ;;
+ t) # specify [t]apefile on local host
+ tapefile="$OPTARG"
+ ;;
+ u) # specify [u]sername for connection
+ username="$OPTARG"
+ ;;
+ v) # be [v]erbose and display what's going on
+ verbose=""
+ tarargs=${tarargs}v
+ ;;
+ '?') # any other switch
+ Usage 2 "Invalid switch specified - abort."
+ ;;
+ esac
+done
+
+shift $(expr $OPTIND - 1)
+
+if [ "$server" = "" ] || [ "$service" = "" ]; then
+ Usage 1 "No server or no service specified - abort."
+fi
+
+# if the -v switch is set, the echo the current parameters
+if [ -z "$verbose" ]; then
+ echo "server is $server"
+# echo "share is $service"
+ echo "share is $service\\$cdcmd"
+ echo "tar args is $tarargs"
+# echo "password is $password" # passwords should never be sent to screen
+ echo "tape is $tapefile"
+ echo "blocksize is $blocksize"
+fi
+
+tarargs=${tarargs}${blocksizearg}${newerarg}
+
+eval $SMBCLIENT "'\\\\$server\\$service'" "'$password'" -U "'$username'" \
+ -E $log -D "'$cdcmd'" ${clientargs} \
+ -T${tarcmd}${tarargs} $blocksize $newer $tapefile '${1+"$@"}' $verbose
diff --git a/source3/script/strip_trail_ws.pl b/source3/script/strip_trail_ws.pl
new file mode 100755
index 0000000..c2c39e2
--- /dev/null
+++ b/source3/script/strip_trail_ws.pl
@@ -0,0 +1,18 @@
+#!/usr/bin/perl -w
+
+open( INFILE, "$ARGV[0]" ) || die $@;
+open( OUTFILE, ">$ARGV[0].new" ) || die $@;
+
+while ( <INFILE> ) {
+ $_ =~ s/[ \t\r]*$//;
+ print OUTFILE "$_";
+}
+
+close( INFILE );
+close( OUTFILE );
+
+rename( "$ARGV[0].new", "$ARGV[0]" ) || die @_;
+
+exit( 0 );
+
+
diff --git a/source3/script/tests/dlopen.sh b/source3/script/tests/dlopen.sh
new file mode 100755
index 0000000..a1299b2
--- /dev/null
+++ b/source3/script/tests/dlopen.sh
@@ -0,0 +1,90 @@
+#!/bin/sh
+#
+# Copyright (C) Nalin Dahyabhai <nalin@redhat.com> 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/>.
+
+tempdir=$(mktemp -d /tmp/dlopenXXXXXX)
+test -n "$tempdir" || exit 1
+cat >>$tempdir/dlopen.c <<_EOF
+#include <dlfcn.h>
+#include <stdio.h>
+#include <limits.h>
+#include <sys/stat.h>
+/* Simple program to see if dlopen() would succeed. */
+int main(int argc, char **argv)
+{
+ int i;
+ struct stat st;
+ char buf[PATH_MAX];
+ for (i = 1; i < argc; i++) {
+ if (dlopen(argv[i], RTLD_NOW)) {
+ fprintf(stdout, "dlopen() of \"%s\" succeeded.\n",
+ argv[i]);
+ } else {
+ snprintf(buf, sizeof(buf), "./%s", argv[i]);
+ if ((stat(buf, &st) == 0) && dlopen(buf, RTLD_NOW)) {
+ fprintf(stdout, "dlopen() of \"./%s\" "
+ "succeeded.\n", argv[i]);
+ } else {
+ fprintf(stdout, "dlopen() of \"%s\" failed: "
+ "%s\n", argv[i], dlerror());
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+_EOF
+
+for arg in "$@"; do
+ case "$arg" in
+ "") ;;
+
+ -I* | -D* | -f* | -m* | -g* | -O* | -W*)
+ cflags="$cflags $arg"
+ ;;
+ -l* | -L*)
+ ldflags="$ldflags $arg"
+ ;;
+ /*)
+ modules="$modules $arg"
+ ;;
+ *)
+ modules="$modules $arg"
+ ;;
+ esac
+done
+
+${CC:-gcc} $RPM_OPT_FLAGS $CFLAGS -o $tempdir/dlopen $cflags $tempdir/dlopen.c $ldflags
+
+retval=0
+for module in $modules; do
+ case "$module" in
+ "") ;;
+
+ /*)
+ $tempdir/dlopen "$module"
+ retval=$?
+ ;;
+ *)
+ $tempdir/dlopen ./"$module"
+ retval=$?
+ ;;
+ esac
+done
+
+rm -f $tempdir/dlopen $tempdir/dlopen.c
+rmdir $tempdir
+exit $retval
diff --git a/source3/script/tests/fake_snap.pl b/source3/script/tests/fake_snap.pl
new file mode 100755
index 0000000..d88307e
--- /dev/null
+++ b/source3/script/tests/fake_snap.pl
@@ -0,0 +1,85 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+use File::Path qw(rmtree);
+use POSIX ();
+
+sub _untaint_path
+{
+ my ($path) = @_;
+
+ if ($path =~ /^(.*)$/) {
+ return $1;
+ }
+ die "bad path";
+}
+
+sub _create_snapshot
+{
+ my ($base_path) = _untaint_path(shift);
+ my $time_str = POSIX::strftime("%Y.%m.%d-%H.%M.%S" , localtime());
+ my $snap_path = $base_path . "/.snapshots/\@GMT-" . $time_str;
+ my $ret;
+
+ delete @ENV{'BASH_ENV'};
+
+ $ENV{'PATH'} = '/bin:/usr/bin'; # untaint PATH
+ POSIX::mkdir($base_path . "/.snapshots", 0755);
+
+ # add trailing slash to src path to ensure that only contents is copied
+ $ret = system("rsync", "-a", "--exclude=.snapshots/", "${base_path}/",
+ $snap_path);
+ if ($ret != 0) {
+ print STDERR "rsync failed with $ret\n";
+ } else {
+ print "$snap_path\n";
+ }
+
+ return $ret;
+}
+
+sub _delete_snapshot
+{
+ my $base_path = _untaint_path(shift);
+ my $snap_path = _untaint_path(shift);
+
+ # we're doing a recursive delete, so do some sanity checks
+ if ((index($snap_path, $base_path) != 0) || (index($snap_path, ".snapshots") == -1)) {
+ print STDERR "invalid snap_path: $snap_path\n";
+ return -1;
+ }
+
+ $ENV{'PATH'} = '/bin:/usr/bin'; # untaint PATH
+ rmtree($snap_path, {error => \my $err});
+ if (@$err) {
+ for my $diag (@$err) {
+ my ($file, $message) = %$diag;
+ if ($file eq '') {
+ print STDERR "rmtree error: $message\n";
+ } else {
+ print STDERR "rmtree error $file: $message\n";
+ }
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+my $ret;
+my $num_args = $#ARGV + 1;
+my $cmd = shift;
+
+if (($num_args == 2) && ($cmd eq "--check")) {
+ $ret = 0;
+} elsif (($num_args == 2) && ($cmd eq "--create")) {
+ $ret = _create_snapshot($ARGV[0]);
+} elsif (($num_args == 3) && ($cmd eq "--delete")) {
+ $ret = _delete_snapshot($ARGV[0], $ARGV[1]);
+} else {
+ print STDERR "invalid script argument\n";
+ $ret = -1;
+}
+
+exit $ret;
diff --git a/source3/script/tests/full_audit_segfault/run.sh b/source3/script/tests/full_audit_segfault/run.sh
new file mode 100755
index 0000000..a2ba43f
--- /dev/null
+++ b/source3/script/tests/full_audit_segfault/run.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+if [ $# -lt 1 ]; then
+ cat <<EOF
+Usage: run.sh VFSTEST
+EOF
+ exit 1
+fi
+
+TALLOC_FILL_FREE=0
+export TALLOC_FILL_FREE
+
+TESTBASE="$(dirname $0)"
+VFSTEST="$VALGRIND $1"
+shift 1
+ADDARGS="$*"
+
+incdir=$(dirname $0)/../../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+testit "vfstest" "$VFSTEST" -f "$TESTBASE/vfstest.cmd" "$ADDARGS" ||
+ failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source3/script/tests/full_audit_segfault/vfstest.cmd b/source3/script/tests/full_audit_segfault/vfstest.cmd
new file mode 100644
index 0000000..84e93e2
--- /dev/null
+++ b/source3/script/tests/full_audit_segfault/vfstest.cmd
@@ -0,0 +1,3 @@
+load full_audit
+connect
+create_file .
diff --git a/source3/script/tests/getset_quota.py b/source3/script/tests/getset_quota.py
new file mode 100755
index 0000000..39d7024
--- /dev/null
+++ b/source3/script/tests/getset_quota.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Tests for smbcquotas
+# Copyright (C) Noel Power 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 sys
+import traceback
+import logging
+import os
+
+USER_QUOTAS = 1
+USER_DEFAULT_QUOTAS = 2
+GROUP_QUOTAS = 3
+GROUP_DEFAULT_QUOTAS = 4
+
+#Quota model
+
+class Quota:
+ def __init__(self):
+ self.flags = 0
+ self.quotatype = USER_DEFAULT_QUOTAS
+ self.uid = 0
+ self.usedblocks = 0
+ self.softlimit = 0
+ self.hardlimit = 0
+ self.hardlimit = 0
+ self.usedinodes = 0
+ self.slimitinodes = 0
+ self.hlimitinodes = 0
+
+def quota_to_str(item):
+ result = str(item.flags) + " " + str(item.usedblocks) + " " + str(item.softlimit) + " " + str(item.hardlimit) + " " + str(item.usedinodes) + " " + str(item.slimitinodes) + " " + str(item.hlimitinodes)
+ return result
+
+def quota_to_db_str(item):
+ result = item.uid + " " + str(item.usedblocks) + " " + str(item.softlimit) + " " + str(item.hardlimit) + " " + str(item.usedinodes) + " " + str(item.slimitinodes) + " " + str(item.hlimitinodes)
+ return result
+
+def load_quotas(input_file):
+ fileContents = open(input_file,"r")
+ lineno = 0
+ quotas = []
+ for line in fileContents:
+ if line.strip().startswith("#"):
+ continue
+ content = line.strip().split()
+ quota = Quota()
+ if len(content) < 7:
+ logging.debug("ignoring line %d, doesn't have enough fields\n"%lineno)
+ else:
+ quota.flags = 2
+ quota.uid = content[0]
+ quota.usedblocks = content[1]
+ quota.softlimit = content[2]
+ quota.hardlimit = content[3]
+ quota.usedinodes = content[4]
+ quota.slimitinodes = content[5]
+ quota.hlimitinodes = content[6]
+ quotas.append(quota)
+
+ fileContents.close()
+ return quotas
+
+def set_quotas(quota_list, output_file):
+ filecontents = open(output_file,"w+")
+ if filecontents == None:
+ return False
+ lines = ""
+ for quota in quota_list:
+ next_line = quota_to_db_str(quota)
+ if next_line:
+ lines = lines + next_line + "\n"
+ filecontents.write(lines)
+ filecontents.close()
+ return True
+
+def get_quotas(uid, quota_list):
+ logging.debug("in get_quotas\n")
+ for quota in quota_list:
+ if quota.uid == uid:
+ return quota
+ return None
+
+def main():
+ logging.basicConfig(format='%(asctime)s %(message)s', level=logging.DEBUG)
+ logging.debug("system args passed are %s\n"% str(sys.argv))
+ quota_file_dir = os.path.dirname(sys.argv[0])
+ quota_file_db = os.path.join(quota_file_dir,"quotas.db")
+ logging.debug("quota db is located %s\n", quota_file_db)
+ quota_list = load_quotas(quota_file_db)
+ logging.debug("quotas loaded have %s entries\n", len(quota_list))
+ result = None
+ if len(sys.argv) == 4:
+ # Get Quota
+ directory = sys.argv[1]
+ if sys.argv[2] == "1":
+ query_type = USER_QUOTAS
+ elif sys.argv[2] == "2":
+ query_type = USER_DEFAULT_QUOTAS
+ elif sys.argv[2] == "3":
+ query_type = GROUP_QUOTAS
+ elif sys.argv[2] == "4":
+ query_type = GROUP_DEFAULT_QUOTAS
+ uid = sys.argv[3]
+ quota = get_quotas(uid, quota_list)
+ if quota is None:
+ logging.debug("no result for uid %s"%uid)
+ else:
+ result = quota_to_str(quota)
+ logging.debug("got result for uid %s\n"%uid)
+ if result is None:
+ result = "0 0 0 0 0 0 0"
+ logging.debug("for uid %s returning quotas %s\n"%(uid,result))
+ print("%s"%result)
+ elif len(sys.argv) > 8:
+ # Set Quota
+ quota = Quota()
+ directory = sys.argv[1]
+ quota.query_type = sys.argv[2]
+ quota.uid = sys.argv[3]
+ quota.flags = sys.argv[4]
+ quota.softlimit = sys.argv[5]
+ quota.hardlimit = sys.argv[6]
+ quota.slimitinodes = sys.argv[7]
+ quota.hlimitinodes = sys.argv[8]
+ found = get_quotas(quota.uid, quota_list)
+ if found:
+ found.query_type = quota.query_type
+ found.uid = quota.uid
+ found.flags = quota.flags
+ found.softlimit = quota.softlimit
+ found.hardlimit = quota.hardlimit
+ found.slimitinodes = quota.slimitinodes
+ found.hlimitinodes = quota.hlimitinodes
+ else:
+ quota_list.append(quota)
+ if set_quotas(quota_list,quota_file_db):
+ print ("%s\n"%quota_to_str(quota_list[-1]))
+ return
+if __name__ == '__main__':
+ main()
diff --git a/source3/script/tests/printing/modprinter.pl b/source3/script/tests/printing/modprinter.pl
new file mode 100755
index 0000000..28817db
--- /dev/null
+++ b/source3/script/tests/printing/modprinter.pl
@@ -0,0 +1,140 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+use Getopt::Long;
+use Cwd qw(abs_path);
+
+my $opt_help = 0;
+my $opt_smb_conf = undef;
+my $opt_add = 0;
+my $opt_delete = 0;
+
+my $result = GetOptions(
+ 'help|h|?' => \$opt_help,
+ 'smb_conf|s=s' => \$opt_smb_conf,
+ 'add|a' => \$opt_add,
+ 'delete|d' => \$opt_delete
+);
+
+sub usage($;$)
+{
+ my ($ret, $msg) = @_;
+
+ print $msg."\n\n" if defined($msg);
+
+ print "usage:
+
+ --help|-h|-? Show this help.
+
+ --smb_conf|-s <path> Path of the 'smb.conf' file.
+
+ --add|-a 'add' a printer.
+ --delete|-d 'delete' a printer.
+
+ printer_name share_name port_name driver_name location XX remote_machine
+";
+ exit($ret);
+}
+
+usage(1) if (not $result);
+
+usage(0) if ($opt_help);
+
+if (!$opt_add && !$opt_delete) {
+ usage(1, "invalid: neither --add|-a nor --delete|-d set");
+}
+
+if (!$opt_smb_conf) {
+ usage(1, "invalid: no smb.conf file set");
+}
+
+my @argv = @ARGV;
+
+my $printer_name = shift(@argv);
+my $share_name = shift(@argv);
+my $port_name = shift(@argv);
+my $driver_name = shift(@argv);
+my $location = shift(@argv);
+my $win9x_driver_location = shift(@argv);
+my $remote_machine = shift(@argv);
+
+if (!defined($share_name) || length($share_name) == 0) {
+ $share_name = $printer_name;
+}
+
+if (!defined($share_name)) {
+ die "share name not defined";
+}
+
+my $smb_conf_file = $opt_smb_conf;
+if ($smb_conf_file =~ /^(.*)$/) {
+ $smb_conf_file = $1; # untaint file name
+} else {
+ die "Invalid file name $smb_conf_file";
+}
+
+my $tmp = $smb_conf_file.$$;
+
+my $section = undef;
+my $within_section = 0;
+my $found_section = 0;
+
+open(CONFIGFILE_NEW, "+>$tmp") || die "Unable top open conf file $tmp";
+
+open (CONFIGFILE, "+<$smb_conf_file") || die "Unable to open config file $smb_conf_file";
+while (<CONFIGFILE>) {
+ my $line = $_;
+ chomp($_);
+ $_ =~ s/^\s*//;
+ $_ =~ s/\s*$//;
+ if (($_ =~ /^#/) || ($_ =~ /^;/)) {
+ print CONFIGFILE_NEW $line;
+ next;
+ }
+ if ($_ =~ /^\[.*\]$/) {
+ $_ = substr($_, 1, length($_)-2);
+ if (length($_)) {
+ $section = $_;
+ } else {
+ die "invalid section found";
+ }
+ if ($section eq $share_name) {
+ $found_section = 1;
+ if ($opt_add) {
+ exit 0;
+# die("share $share_name already exists\n");
+ }
+ if ($opt_delete) {
+ $within_section = 1;
+ next;
+ }
+ } else {
+ print CONFIGFILE_NEW $line;
+ $within_section = 0;
+ }
+ next;
+ } else {
+ if ($within_section == 1) {
+ next;
+ }
+ print CONFIGFILE_NEW $line;
+ }
+}
+if ($opt_add) {
+ print CONFIGFILE_NEW "[$share_name]\n\tprintable = yes\n\tpath = /tmp\n";
+}
+close (CONFIGFILE);
+close (CONFIGFILE_NEW);
+
+if ($opt_delete && ($found_section == 0)) {
+ die "share $share_name not found";
+}
+
+delete @ENV{"BASH_ENV"};
+
+$ENV{'PATH'} = '/bin:/usr/bin'; # untaint PATH
+system("cp", "$tmp", "$smb_conf_file");
+unlink $tmp;
+
+exit 0;
diff --git a/source3/script/tests/printing/printing_var_exp_lpr_cmd.sh b/source3/script/tests/printing/printing_var_exp_lpr_cmd.sh
new file mode 100755
index 0000000..c25b49a
--- /dev/null
+++ b/source3/script/tests/printing/printing_var_exp_lpr_cmd.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+logfile="${SELFTEST_TMPDIR}/${USER}_printing_var_exp.log"
+
+rm -f "$logfile"
+
+for i in $(seq 1 $#); do
+ eval echo "arg $i: \$$i" >>"$logfile"
+done
diff --git a/source3/script/tests/smbspool_argv_wrapper.c b/source3/script/tests/smbspool_argv_wrapper.c
new file mode 100644
index 0000000..6f84f3b
--- /dev/null
+++ b/source3/script/tests/smbspool_argv_wrapper.c
@@ -0,0 +1,72 @@
+/*
+ Wrapper for smbspool to test Device URI in argv[0]
+
+ Copyright (C) Bryan Mason 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 <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+
+/*
+ * Before calling a backend like smbspool, CUPS will set argv[0] to
+ * the Device URI. This program wraps a program like smbspool and
+ * sets argv[0] to the device URI before exec()ing the actual backend
+ * program.
+ */
+
+int main(int argc, char *argv[], char *envp[])
+{
+ char **new_argv;
+ char *exec_path;
+ int a;
+ int rv;
+/*
+ * Expected parameters:
+ *
+ * smbspool_argv_wrapper smbspool uri job user title copies opts file(s)
+ * argv[0] 1 2 3 4 5 6 7 8
+ *
+ */
+ /* Allocate memory for the new arguments (exit on failure). */
+ new_argv = calloc(argc, sizeof(char *));
+ if (new_argv == 0) {
+ exit(ENOMEM);
+ }
+
+ /* Save the path to the smbspool executable */
+ exec_path = argv[1];
+
+ /*
+ * Shift the rest of the args so smbspool is called with:
+ *
+ * uri job user title copies opts file(s)
+ * argv[0] 1 2 3 4 5 6
+ */
+
+ for (a = 2; a < argc; a++) {
+ new_argv[a-2] = argv[a];
+ }
+
+ /* Execute smbspool with new arguments */
+ rv = execve(exec_path, new_argv, envp);
+ if (rv == -1) {
+ exit(errno);
+ }
+
+ /* Avoid compiler error/warning */
+ return 0;
+}
diff --git a/source3/script/tests/stream-depot/run.sh b/source3/script/tests/stream-depot/run.sh
new file mode 100755
index 0000000..bcc85b6
--- /dev/null
+++ b/source3/script/tests/stream-depot/run.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+if [ $# -lt 2 ]; then
+ cat <<EOF
+Usage: run.sh VFSTEST PREFIX
+EOF
+ exit 1
+fi
+
+TESTBASE=$(dirname $0)
+VFSTEST=$1
+PREFIX=$2
+shift 2
+ADDARGS="$*"
+
+VFSTEST_PREFIX=vfstest
+VFSTEST_TMPDIR=$(mktemp -d ${PREFIX}/${VFSTEST_PREFIX}_XXXXXX)
+
+incdir=$(dirname $0)/../../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+cd $VFSTEST_TMPDIR || exit 1
+
+testit "vfstest" $VFSTEST -f $TESTBASE/vfstest.cmd $ADDARGS || failed=$(expr $failed + 1)
+testname=".streams check"
+subunit_start_test $testname
+NUM=$(find .streams | wc -l)
+if [ $NUM -ne 3 ]; then
+ echo "streams_depot left ${NUM} in .streams, expected 3" | subunit_fail_test $testname
+ failed=$(expr $failed + 1)
+else
+ subunit_pass_test $testname
+fi
+
+exit $failed
diff --git a/source3/script/tests/stream-depot/vfstest.cmd b/source3/script/tests/stream-depot/vfstest.cmd
new file mode 100644
index 0000000..1400546
--- /dev/null
+++ b/source3/script/tests/stream-depot/vfstest.cmd
@@ -0,0 +1,5 @@
+connect
+mkdir x
+open x:y RC 0770
+unlink x:y
+rmdir x
diff --git a/source3/script/tests/test_acl_xattr.sh b/source3/script/tests/test_acl_xattr.sh
new file mode 100755
index 0000000..d0eec66
--- /dev/null
+++ b/source3/script/tests/test_acl_xattr.sh
@@ -0,0 +1,156 @@
+#!/bin/sh
+
+# this tests acl_xattr config parameter "ignore system acl"
+
+if [ $# -lt 6 ]; then
+ cat <<EOF
+Usage: $0 SERVER USERNAME PASSWORD PREFIX SMBCLIENT SMBCACLS
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+USERNAME="$2"
+PASSWORD="$3"
+PREFIX="$4"
+SMBCLIENT="$5"
+SMBCACLS="$6"
+shift 6
+ADDARGS="$*"
+SMBCLIENT="$VALGRIND ${SMBCLIENT} ${ADDARGS}"
+SMBCACLS="$VALGRIND ${SMBCACLS} ${ADDARGS}"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+setup_remote_file()
+{
+ local share=$1
+ local fname="$share.$$"
+ local local_fname=$PREFIX/$fname
+ touch $local_fname
+ $SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "rm $fname"
+ $SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "ls" | grep "$fname" && exit 1
+ $SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "lcd $PREFIX; put $fname" || exit 1
+}
+
+smbcacls_x()
+{
+ local share=$1
+ local fname="$share.$$"
+
+ # skip with SMB1
+ echo "$ADDARGS" | grep mNT1 && exit 0
+
+ $SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD "$fname" -x || exit 1
+ mxac=$($SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD "$fname" -x | awk '/Maximum access/ {print $3}')
+
+ echo "mxac: $mxac"
+ if test "$mxac" != "0x1f01ff"; then
+ exit 1
+ fi
+}
+
+nt_affects_posix()
+{
+ local share=$1
+ local expected=$2
+ local b4
+ local af
+ local fname="$share.$$"
+ b4=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null) || exit 1
+ $SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD -a "ACL:$SERVER\force_user:ALLOWED/0x0/READ" 2>/dev/null || exit 1
+ af=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null) || exit 1
+ echo "before: $b4"
+ echo "after: $af"
+ echo "${b4}" | grep -q "^# owner:" || exit 1
+ echo "${af}" | grep -q "^# owner:" || exit 1
+ if test "$expected" = "true"; then
+ test "$b4" != "$af"
+ else
+ test "$b4" = "$af"
+ fi
+}
+
+nt_affects_chown()
+{
+ local share=$1
+ local b4_expected
+ local af_expected
+ local b4_actual
+ local af_actual
+ local fname="$share.$$"
+
+ echo -n "determining uid of $USERNAME..."
+ b4_expected=$(getent passwd $USERNAME) || exit 1
+ b4_expected=$(echo "$b4_expected" | awk -F: '{print $3}')
+ echo "$b4_expected"
+
+ echo -n "determining uid of force_user..."
+ af_expected=$(getent passwd force_user) || exit 1
+ af_expected=$(echo "$af_expected" | awk -F: '{print $3}')
+ echo "$af_expected"
+
+ #basic sanity...
+ test "$b4_expected != $af_expected" || exit 1
+
+ b4_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null) || exit 1
+ echo "${b4_actual}" | grep -q "^# owner:" || exit 1
+ b4_actual=$(echo "$b4_actual" | sed -rn 's/^# owner: (.*)/\1/p')
+ $SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD -a "ACL:$SERVER\force_user:ALLOWED/0x0/FULL" || exit 1
+ $SMBCACLS //$SERVER/$share $fname -U force_user%$PASSWORD -C force_user 2>/dev/null || exit 1
+ af_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null) || exit 1
+ echo "${af_actual}" | grep -q "^# owner:" || exit 1
+ af_actual=$(echo "$af_actual" | sed -rn 's/^# owner: (.*)/\1/p')
+ echo "before: $b4_actual"
+ echo "after: $af_actual"
+ test "$b4_expected" = "$b4_actual" && test "$af_expected" = "$af_actual"
+}
+
+nt_affects_chgrp()
+{
+ local share=$1
+ local b4_expected
+ local af_expected
+ local b4_actual
+ local af_actual
+ local fname="$share.$$"
+
+ echo -n "determining gid of domusers..."
+ b4_expected=$(getent group domusers) || exit 1
+ b4_expected=$(echo "$b4_expected" | awk -F: '{print $3}')
+ echo "$b4_expected"
+
+ echo -n "determining gid of domadmins..."
+ af_expected=$(getent group domadmins) || exit 1
+ af_expected=$(echo "$af_expected" | awk -F: '{print $3}')
+ echo "$af_expected"
+
+ #basic sanity...
+ test "$b4_expected" != "$af_expected" || exit 1
+
+ b4_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null) || exit 1
+ echo "${b4_actual}" | grep -q "^# group:" || exit 1
+ b4_actual=$(echo "$b4_actual" | sed -rn 's/^# group: (.*)/\1/p')
+ $SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD -G domadmins 2>/dev/null || exit 1
+ af_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null) || exit 1
+ echo "${af_actual}" | grep -q "^# group:" || exit 1
+ af_actual=$(echo "$af_actual" | sed -rn 's/^# group: (.*)/\1/p')
+ echo "before: $b4_actual"
+ echo "after: $af_actual"
+ test "$af_expected" != "$b4_actual" && test "$af_expected" = "$af_actual"
+}
+
+testit "setup remote file tmp" setup_remote_file tmp
+testit "setup remote file ign_sysacls" setup_remote_file ign_sysacls
+testit "smbcacls -x" smbcacls_x tmp
+testit "nt_affects_posix tmp" nt_affects_posix tmp "true"
+testit "nt_affects_posix ign_sysacls" nt_affects_posix ign_sysacls "false"
+testit "setup remote file tmp" setup_remote_file tmp
+testit "setup remote file ign_sysacls" setup_remote_file ign_sysacls
+testit "nt_affects_chown tmp" nt_affects_chown tmp
+testit "nt_affects_chown ign_sysacls" nt_affects_chown ign_sysacls
+testit "setup remote file tmp" setup_remote_file tmp
+testit "setup remote file ign_sysacls" setup_remote_file ign_sysacls
+testit "nt_affects_chgrp tmp" nt_affects_chgrp tmp
+testit "nt_affects_chgrp ign_sysacls" nt_affects_chgrp ign_sysacls
diff --git a/source3/script/tests/test_aio_outstanding.sh b/source3/script/tests/test_aio_outstanding.sh
new file mode 100755
index 0000000..a497181
--- /dev/null
+++ b/source3/script/tests/test_aio_outstanding.sh
@@ -0,0 +1,99 @@
+#!/usr/bin/env bash
+#
+# Test terminating an smbclient connection with outstanding
+# aio requests.
+#
+# Note this is designed to be run against
+# the aio_delay_inject share which is preconfigured
+# with 2 second delays on pread/pwrite.
+
+if [ $# -lt 4 ]; then
+ echo Usage: test_aio_outstanding.sh \
+ SERVERCONFFILE SMBCLIENT IP aio_delay_inject_sharename
+ exit 1
+fi
+
+CONF=$1
+SMBCLIENT=$2
+SERVER=$3
+SHARE=$4
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+cd $SELFTEST_TMPDIR || exit 1
+
+#
+# Note if we already have any panics in the smbd log.
+#
+panic_count_0=$(grep -c PANIC $SMBD_TEST_LOG)
+
+# Create the smbclient communication pipes.
+rm -f smbclient-stdin smbclient-stdout smbclient-stderr
+mkfifo smbclient-stdin smbclient-stdout smbclient-stderr
+
+# Create a large-ish testfile
+rm aio_outstanding_testfile
+head -c 20MB /dev/zero >aio_outstanding_testfile
+
+CLI_FORCE_INTERACTIVE=1
+export CLI_FORCE_INTERACTIVE
+
+${SMBCLIENT} //${SERVER}/${SHARE} ${CONF} -U${USER}%${PASSWORD} \
+ <smbclient-stdin >smbclient-stdout 2>smbclient-stderr &
+CLIENT_PID=$!
+
+sleep 1
+
+exec 100>smbclient-stdin 101<smbclient-stdout 102<smbclient-stderr
+
+# consume the smbclient startup messages
+head -n 1 <&101
+
+# Ensure we're putting a fresh file.
+echo "del aio_outstanding_testfile" >&100
+echo "put aio_outstanding_testfile" >&100
+
+sleep 2
+
+# Terminate the smbclient write to the aio_delay_inject share whilst
+# we have outstanding writes.
+kill $CLIENT_PID
+
+sleep 1
+
+# Ensure the panic count didn't change.
+#
+# BUG: https://bugzilla.samba.org/show_bug.cgi?id=14301
+#
+
+panic_count_1=$(grep -c PANIC $SMBD_TEST_LOG)
+
+# Rerun smbclient to remove the testfile on the server.
+rm -f smbclient-stdin smbclient-stdout smbclient-stderr aio_outstanding_testfile
+mkfifo smbclient-stdin smbclient-stdout
+
+${SMBCLIENT} //${SERVER}/${SHARE} ${CONF} -U${USER}%${PASSWORD} \
+ <smbclient-stdin >smbclient-stdout &
+
+sleep 1
+
+exec 100>smbclient-stdin 101<smbclient-stdout
+
+echo "del aio_outstanding_testfile" >&100
+echo "exit" >&100
+
+sleep 2
+
+rm -f smbclient-stdin smbclient-stdout aio_outstanding_testfile
+
+testit "check_panic" test $panic_count_0 -eq $panic_count_1 ||
+ failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_async_req.sh b/source3/script/tests/test_async_req.sh
new file mode 100755
index 0000000..27b4680
--- /dev/null
+++ b/source3/script/tests/test_async_req.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+SOCKET_WRAPPER_IPV4_NETWORK="127.0.0.0"
+export SOCKET_WRAPPER_IPV4_NETWORK
+
+testit "async_connect_send" $VALGRIND $BINDIR/async_connect_send_test ||
+ failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_bad_auditnames.sh b/source3/script/tests/test_bad_auditnames.sh
new file mode 100755
index 0000000..69ddf14
--- /dev/null
+++ b/source3/script/tests/test_bad_auditnames.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+# this tests a full audit share with bad VFS
+# names will not allow connection.
+# BUG: https://bugzilla.samba.org/show_bug.cgi?id=15098
+
+if [ $# -lt 5 ]; then
+ cat <<EOF
+Usage: $0 SERVER SHARE USERNAME PASSWORD SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+SHARE="$2"
+USERNAME="$3"
+PASSWORD="$4"
+SMBCLIENT="$5"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir/subunit.sh"
+
+can_connect()
+{
+ $SMBCLIENT //"$SERVER"/"$SHARE" -U"$USERNAME"%"$PASSWORD" -c "ls" | grep "tree connect failed: NT_STATUS_UNSUCCESSFUL" >/dev/null 2>&1
+}
+
+testit "Cannot connect to share $SHARE" can_connect || failed=$((failed + 1))
diff --git a/source3/script/tests/test_bug15435_widelink_dfs.sh b/source3/script/tests/test_bug15435_widelink_dfs.sh
new file mode 100755
index 0000000..f0705ca
--- /dev/null
+++ b/source3/script/tests/test_bug15435_widelink_dfs.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# regression test for dfs access with wide links enabled on dfs share
+
+if [ $# -lt 5 ]; then
+ cat <<EOF
+Usage: test_bug15435_widelink_dfs.sh SERVER SERVER_IP USERNAME PASSWORD SMBCLIENT CONFIGURATION <smbclient arguments>
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+SERVER_IP="$2"
+USERNAME="$3"
+PASSWORD="$4"
+smbclient="$5"
+CONFIGURATION="$6"
+shift 6
+ADDARGS="$@"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+. $incdir/common_test_fns.inc
+
+# TEST
+test_smbclient "smbclient as $DOMAIN\\$USERNAME" 'ls' "//$SERVER/msdfs-share-wl" -U$DOMAIN\\$USERNAME%$PASSWORD $ADDARGS -c 'cd msdfs-src1' || failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source3/script/tests/test_chdir_cache.sh b/source3/script/tests/test_chdir_cache.sh
new file mode 100755
index 0000000..29f54d1
--- /dev/null
+++ b/source3/script/tests/test_chdir_cache.sh
@@ -0,0 +1,122 @@
+#!/usr/bin/env bash
+#
+# Ensure we get a chdir_current_service error if CHDIR fails with EACCESS
+# for an SMB2 request.
+#
+# BUG:https://bugzilla.samba.org/show_bug.cgi?id=14682
+#
+# Copyright (C) 2021 Jeremy Allison
+
+if [ $# -lt 5 ]; then
+ echo Usage: test_chdir_cache.sh \
+ --configfile=SERVERCONFFILE SMBCLIENT SMBCONTROL SERVER SHARE PREFIX TESTENV
+ exit 1
+fi
+
+CONF=$1
+shift 1
+SMBCLIENT=$1
+shift 1
+SMBCONTROL=$1
+shift 1
+SERVER=$1
+shift 1
+SHARE=$1
+shift 1
+PREFIX=${1}
+shift 1
+TESTENV=${1}
+shift 1
+
+PREFIX_ABS="$(readlink -f "${PREFIX}")"
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+conf_dir=$(dirname ${SERVERCONFFILE})
+
+error_inject_conf=${conf_dir}/error_inject.conf
+rm -f ${error_inject_conf}
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+cd $SELFTEST_TMPDIR || exit 1
+
+rm -f smbclient-stdin smbclient-stdout smbclient-stderr
+mkfifo smbclient-stdin smbclient-stdout smbclient-stderr
+
+CLI_FORCE_INTERACTIVE=1
+export CLI_FORCE_INTERACTIVE
+
+${SMBCLIENT} //${SERVER}/${SHARE} ${CONF} -U${USER}%${PASSWORD} \
+ <smbclient-stdin >smbclient-stdout 2>smbclient-stderr &
+CLIENT_PID=$!
+
+log_file="${PREFIX_ABS}/${TESTENV}/smbd_test.log"
+# Add support for "SMBD_DONT_LOG_STDOUT=1"
+if [ -r "${PREFIX_ABS}/${TESTENV}/logs/log.smbd" ]; then
+ log_file="${PREFIX_ABS}/${TESTENV}/logs/log.smbd"
+fi
+
+# Count the number of chdir_current_service: vfs_ChDir.*failed: Permission denied
+# errors that are already in the log (should be zero).
+num_errs=$(grep "chdir_current_service: vfs_ChDir.*failed: Permission denied" ${log_file} | wc -l)
+
+sleep 1
+
+exec 100>smbclient-stdin 101<smbclient-stdout 102<smbclient-stderr
+
+# consume the smbclient startup messages
+head -n 1 <&101
+
+# Do an 'ls' as ${USER} to make sure we've done a CHDIR into
+# the share directory.
+echo "ls" >&100
+
+# consume the smbclient output
+head -n 4 <&101
+
+# Now change user to user2, and connect to the share.
+# This should leave us in the same share directory.
+echo "logon user2 ${PASSWORD}" >&100
+echo "tcon ${SHARE}" >&100
+
+# consume the smbclient output
+head -n 4 <&101
+
+# Ensure any chdir will give EACCESS.
+echo "error_inject:chdir = EACCES" >${error_inject_conf}
+testit "reload config 1" \
+ "${SMBCONTROL}" "${CONF}" smbd reload-config ||
+ failed=$((failed + 1))
+
+sleep 1
+
+# Do an 'ls' as user2. Changing users should have
+# deleted the CHDIR cache, so we should now see
+# a chdir_current_service: vfs_ChDir.*failed: Permission denied
+# error message in the log.
+echo 'ls' >&100
+
+kill ${CLIENT_PID}
+rm -f smbclient-stdin smbclient-stdout smbclient-stderr
+
+# Remove the chdir inject.
+rm -f ${error_inject_conf}
+testit "reload config 2" \
+ "${SMBCONTROL}" "${CONF}" smbd reload-config ||
+ failed=$((failed + 1))
+
+# Now look for chdir_current_service: vfs_ChDir.*failed: Permission denied
+# in the smb log. There should be one more than before.
+
+num_errs1=$(grep "chdir_current_service: vfs_ChDir.*failed: Permission denied" ${log_file} | wc -l)
+
+testit "Verify we got at least one chdir error" \
+ test $num_errs1 -gt $num_errs || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_close_denied_share.sh b/source3/script/tests/test_close_denied_share.sh
new file mode 100755
index 0000000..2e6e285
--- /dev/null
+++ b/source3/script/tests/test_close_denied_share.sh
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+#
+# Test smbcontrol close-denied-share command.
+#
+# Copyright (C) 2020 Volker Lendecke
+
+if [ $# -lt 6 ]; then
+ echo Usage: test_close_denied_share.sh \
+ SERVERCONFFILE SHARESEC SMBCLIENT SMBCONTROL IP SHARE
+ exit 1
+fi
+
+CONF=$1
+SHARESEC=$2
+SMBCLIENT=$3
+SMBCONTROL=$4
+SERVER=$5
+SHARE=$6
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+cd $SELFTEST_TMPDIR || exit 1
+
+rm -f smbclient-stdin smbclient-stdout
+mkfifo smbclient-stdin smbclient-stdout
+
+CLI_FORCE_INTERACTIVE=1
+export CLI_FORCE_INTERACTIVE
+
+${SMBCLIENT} //${SERVER}/${SHARE} ${CONF} -U${USER}%${PASSWORD} \
+ <smbclient-stdin >smbclient-stdout &
+CLIENT_PID=$!
+
+sleep 1
+
+exec 100>smbclient-stdin 101<smbclient-stdout
+
+# consume the smbclient startup message
+
+head -n 1 <&101
+
+testit "smbcontrol" ${SMBCONTROL} ${CONF} smbd close-denied-share ${SHARE} ||
+ failed=$(expr $failed + 1)
+sleep 1
+
+echo dir >&100
+
+COUNT=$(head -n 2 <&101 |
+ grep NT_STATUS_NETWORK_NAME_DELETED |
+ wc -l)
+testit "Verify close-denied-share did not kill valid client" \
+ test $COUNT -eq 0 || failed=$(expr $failed + 1)
+
+testit "Deny access" ${SHARESEC} ${CONF} --replace S-1-1-0:DENIED/0x0/FULL \
+ ${SHARE} || failed=$(expr $failed + 1)
+
+testit "smbcontrol" ${SMBCONTROL} ${CONF} smbd close-denied-share ${SHARE} ||
+ failed=$(expr $failed + 1)
+sleep 1
+
+echo dir >&100
+
+COUNT=$(head -n 2 <&101 |
+ grep NT_STATUS_NETWORK_NAME_DELETED |
+ wc -l)
+testit "Verify close-denied-share did kill now-invalid client" \
+ test $COUNT -eq 1 || failed=$(expr $failed + 1)
+
+kill ${CLIENT_PID}
+rm -f smbclient-stdin smbclient-stdout
+
+testit "Allow access" ${SHARESEC} ${CONF} --replace S-1-1-0:ALLOWED/0x0/FULL \
+ ${SHARE} || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_deadtime.sh b/source3/script/tests/test_deadtime.sh
new file mode 100755
index 0000000..3d6368e
--- /dev/null
+++ b/source3/script/tests/test_deadtime.sh
@@ -0,0 +1,67 @@
+#!/usr/bin/env bash
+#
+# Test deadtime parameter
+#
+
+if [ $# -lt 1 ]; then
+ echo Usage: test_deadtime.sh IP
+ exit 1
+fi
+
+server=$1
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+. $incdir/common_test_fns.inc
+
+failed=0
+
+smbclient="$BINDIR/smbclient"
+smbcontrol="$BINDIR/smbcontrol"
+
+global_inject_conf=$(dirname $SMB_CONF_PATH)/global_inject.conf
+
+echo "deadtime = 1" >$global_inject_conf
+$smbcontrol smbd reload-config
+
+cd $SELFTEST_TMPDIR || exit 1
+
+# Create the smbclient communication pipes.
+rm -f smbclient-stdin smbclient-stdout smbclient-stderr
+mkfifo smbclient-stdin smbclient-stdout smbclient-stderr
+
+export CLI_FORCE_INTERACTIVE=1
+export SAMBA_DEPRECATED_SUPPRESS=1
+
+# This gets inherited by smbclient and is required to smbclient doesn't get
+# killed by an unhandled SIGPIPE when writing an SMB2 KEEPALIVE packet to the
+# connection fd that was already closed by the server.
+trap "" SIGPIPE
+
+$smbclient //$server/tmp -U${USER}%${PASSWORD} \
+ <smbclient-stdin >smbclient-stdout 2>smbclient-stderr &
+client_pid=$!
+
+sleep 1
+
+exec 100>smbclient-stdin 101<smbclient-stdout 102<smbclient-stderr
+
+# consume the smbclient startup message
+head -n 1 <&101
+
+sleep 70
+
+err=$(head -n 1 <&102)
+echo "err: $err"
+
+kill $client_pid
+
+echo "$err" | grep NT_STATUS_CONNECTION_DISCONNECTED
+testit "deadtime" test $? -eq 0 || failed=$(expr $failed + 1)
+
+echo "" >$global_inject_conf
+$smbcontrol smbd reload-config
+
+rm -f smbclient-stdin smbclient-stdout smbclient-stderr
+
+testok $0 $failed
diff --git a/source3/script/tests/test_delete_stream.sh b/source3/script/tests/test_delete_stream.sh
new file mode 100755
index 0000000..43d591e
--- /dev/null
+++ b/source3/script/tests/test_delete_stream.sh
@@ -0,0 +1,123 @@
+#!/bin/sh
+#
+# this verifies that deleting a stream uses the correct ACL
+# when using vfs_acl_xattr.
+#
+
+if [ $# -lt 9 ]; then
+ echo "Usage: $0 SERVER SERVER_IP USERNAME PASSWORD PREFIX SMBCLIENT SMBCACLS NET SHARE"
+ exit 1
+fi
+
+SERVER="$1"
+SERVER_IP="$2"
+USERNAME="$3"
+PASSWORD="$4"
+PREFIX="$5"
+SMBCLIENT="$6"
+SMBCACLS="$7"
+NET="$8"
+SHARE="$9"
+
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+SMBCACLS="$VALGRIND ${SMBCACLS}"
+NET="$VALGRIND ${NET}"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+
+setup_testfile()
+{
+ touch $PREFIX/file
+ echo stream > $PREFIX/stream
+
+ $SMBCLIENT //$SERVER/$SHARE -U $USERNAME%$PASSWORD -c "mkdir dir" || return 1
+ $SMBCLIENT //$SERVER/$SHARE -U $USERNAME%$PASSWORD -c "lcd $PREFIX; put file dir/file" || return 1
+ $SMBCLIENT //$SERVER/$SHARE -U $USERNAME%$PASSWORD -c "lcd $PREFIX; put stream dir/file:stream" || return 1
+
+ rm $PREFIX/file
+ rm $PREFIX/stream
+
+ #
+ # Add full control ACE to the file and an ACL without "DELETE" on the
+ # parent directory
+ #
+
+ $SMBCACLS //$SERVER/$SHARE -U $USERNAME%$PASSWORD -S "ACL:Everyone:ALLOWED/0x0/0x1bf" dir || return 1
+ $SMBCACLS //$SERVER/$SHARE -U $USERNAME%$PASSWORD -a "ACL:Everyone:ALLOWED/0x0/0x101ff" dir/file || return 1
+}
+
+remove_testfile()
+{
+ $SMBCACLS //$SERVER/$SHARE -U $USERNAME%$PASSWORD -S "ACL:Everyone:ALLOWED/0x0/0x101ff" dir/file || return 1
+ $SMBCACLS //$SERVER/$SHARE -U $USERNAME%$PASSWORD -S "ACL:Everyone:ALLOWED/0x0/0x101ff" dir || return 1
+ $SMBCLIENT //$SERVER/$SHARE -U $USERNAME%$PASSWORD -c "rm dir/file" || return 1
+ $SMBCLIENT //$SERVER/$SHARE -U $USERNAME%$PASSWORD -c "rmdir dir" || return 1
+}
+
+set_win_owner()
+{
+ local owner=$1
+
+ $SMBCACLS //$SERVER/$SHARE dir/file -U $USERNAME%$PASSWORD -C "$owner" || return 1
+}
+
+delete_stream()
+{
+ #
+ # Setup a file with a stream where we're not the owner and
+ # have delete rights. Bug 15126 would trigger a fallback to
+ # "acl_xattr:default acl style" because fetching the stored
+ # ACL would fail. The stored ACL allows deleting the stream
+ # but the synthesized default ACL does not, so the deletion
+ # of the stream should work, but it fails if we have the bug.
+ #
+
+ # Now try deleting the stream
+ out=$($SMBCLIENT //$SERVER/$SHARE -U $USERNAME%$PASSWORD -c "wdel 0x20 dir/file:stream") || return 1
+
+ #
+ # Bail out in case we get any sort of NT_STATUS_* error, should be
+ # NT_STATUS_ACCESS_DENIED, but let's not slip through any other error.
+ #
+ echo "$out" | grep NT_STATUS_ && return 1
+
+ return 0
+}
+
+win_owner_is()
+{
+ local expected_owner=$1
+ local actual_owner
+
+ $SMBCACLS //$SERVER/$SHARE dir/file -U $USERNAME%$PASSWORD
+ actual_owner=$($SMBCACLS //$SERVER/$SHARE dir/file -U $USERNAME%$PASSWORD | sed -rn 's/^OWNER:(.*)/\1/p')
+ echo "actual_owner = $actual_owner"
+ if ! test "x$actual_owner" = "x$expected_owner"; then
+ echo "Actual owner of dir/file is $actual_owner', expected $expected_owner"
+ return 1
+ fi
+ return 0
+}
+
+# Create a testfile
+testit "create testfile" setup_testfile $SHARE || exit 1
+
+# Grant SeRestorePrivilege to the user so we can change the owner
+testit "grant SeRestorePrivilege" $NET rpc rights grant $USERNAME SeRestorePrivilege -U $USERNAME%$PASSWORD -I $SERVER_IP || exit 1
+
+# We have SeRestorePrivilege, so both give and take ownership must succeed
+testit "give owner with SeRestorePrivilege" set_win_owner "$SERVER\user1" || exit 1
+testit "verify owner" win_owner_is "$SERVER/user1" || exit 1
+
+# Now try to remove the stream on the testfile
+testit "delete stream" delete_stream $SHARE afile || exit 1
+
+# Remove testfile
+testit "remove testfile" remove_testfile $SHARE || exit 1
+
+# Revoke SeRestorePrivilege, give ownership must fail now with NT_STATUS_INVALID_OWNER
+testit "revoke SeRestorePrivilege" $NET rpc rights revoke $USERNAME SeRestorePrivilege -U $USERNAME%$PASSWORD -I $SERVER_IP || exit 1
+
+exit 0
diff --git a/source3/script/tests/test_delete_veto_files_only_rmdir.sh b/source3/script/tests/test_delete_veto_files_only_rmdir.sh
new file mode 100755
index 0000000..08f257f
--- /dev/null
+++ b/source3/script/tests/test_delete_veto_files_only_rmdir.sh
@@ -0,0 +1,182 @@
+#!/bin/sh
+#
+# Check smbclient can (or cannot) delete a directory containing dangling symlinks.
+# BUG: https://bugzilla.samba.org/show_bug.cgi?id=14879
+#
+
+if [ $# -lt 6 ]; then
+ cat <<EOF
+Usage: $0 SERVER SERVER_IP USERNAME PASSWORD SHAREPATH SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER=${1}
+SERVER_IP=${2}
+USERNAME=${3}
+PASSWORD=${4}
+SHAREPATH=${5}
+SMBCLIENT=${6}
+shift 6
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+ADDARGS="$@"
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+rmdir_path="$SHAREPATH/dir"
+
+#
+# Using the share "[delete_veto_files_only]" we CAN delete
+# a directory containing only a dangling symlink.
+#
+test_dangle_symlink_delete_veto_rmdir()
+{
+ local dangle_symlink_path="$rmdir_path/bad_link"
+ local tmpfile=$PREFIX/smbclient.in.$$
+
+ # Create rmdir directory.
+ mkdir -p "$rmdir_path"
+ # Create dangling symlink underneath.
+ ln -s "nowhere-foo" "$dangle_symlink_path"
+
+ cat >"$tmpfile" <<EOF
+cd dir
+ls
+quit
+EOF
+
+ local cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT //$SERVER/delete_veto_files_only -U$USERNAME%$PASSWORD $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+
+ # Check for smbclient error.
+ if [ $ret != 0 ]; then
+ echo "Failed accessing share delete_veto_files_only - $ret"
+ echo "$out"
+ return 1
+ fi
+
+ # We should NOT see the dangling symlink file.
+ echo "$out" | grep bad_link
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "Saw dangling symlink bad_link in share delete_veto_files_only"
+ echo "$out"
+ return 1
+ fi
+
+ # Try and remove the directory, should succeed.
+ cat >"$tmpfile" <<EOF
+rd dir
+quit
+EOF
+
+ local cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT //$SERVER/delete_veto_files_only -U$USERNAME%$PASSWORD $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+
+ # Check for smbclient error.
+ if [ $ret != 0 ]; then
+ echo "Failed accessing share delete_veto_files_only - $ret"
+ echo "$out"
+ return 1
+ fi
+
+ # We should get no NT_STATUS_ errors.
+ echo "$out" | grep NT_STATUS_
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "Got error NT_STATUS_ in share delete_veto_files_only"
+ echo "$out"
+ return 1
+ fi
+
+ return 0
+}
+
+#
+# Using the share "[veto_files_nodelete]" we CANNOT delete
+# a directory containing only a dangling symlink.
+#
+test_dangle_symlink_veto_files_nodelete()
+{
+ local dangle_symlink_path="$rmdir_path/bad_link"
+ local tmpfile=$PREFIX/smbclient.in.$$
+
+ # Create rmdir directory.
+ mkdir -p "$rmdir_path"
+ # Create dangling symlink underneath.
+ ln -s "nowhere-foo" "$dangle_symlink_path"
+
+ cat >"$tmpfile" <<EOF
+cd dir
+ls
+quit
+EOF
+
+ local cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT //$SERVER/veto_files_nodelete -U$USERNAME%$PASSWORD $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+
+ # Check for smbclient error.
+ if [ $ret != 0 ]; then
+ echo "Failed accessing share veto_files_nodelete - $ret"
+ echo "$out"
+ return 1
+ fi
+
+ # We should NOT see the dangling symlink file.
+ echo "$out" | grep bad_link
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "Saw dangling symlink bad_link in share veto_files_nodelete"
+ echo "$out"
+ return 1
+ fi
+
+ # Try and remove the directory, should fail with DIRECTORY_NOT_EMPTY.
+ cat >"$tmpfile" <<EOF
+rd dir
+quit
+EOF
+
+ local cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT //$SERVER/veto_files_nodelete -U$USERNAME%$PASSWORD $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+
+ # Check for smbclient error.
+ if [ $ret != 0 ]; then
+ echo "Failed accessing share veto_files_nodelete - $ret"
+ echo "$out"
+ return 1
+ fi
+
+ # We should get NT_STATUS_DIRECTORY_NOT_EMPTY errors.
+ echo "$out" | grep NT_STATUS_DIRECTORY_NOT_EMPTY
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "Should get NT_STATUS_DIRECTORY_NOT_EMPTY in share veto_files_nodelete"
+ echo "$out"
+ return 1
+ fi
+
+ return 0
+}
+
+testit "rmdir can delete directory containing dangling symlink" \
+ test_dangle_symlink_delete_veto_rmdir || failed=$(expr "$failed" + 1)
+
+rm -rf "$rmdir_path"
+
+testit "rmdir cannot delete directory delete_veto_files_no containing dangling symlink" \
+ test_dangle_symlink_veto_files_nodelete || failed=$(expr "$failed" + 1)
+
+rm -rf "$rmdir_path"
+exit "$failed"
diff --git a/source3/script/tests/test_dfree_command.sh b/source3/script/tests/test_dfree_command.sh
new file mode 100755
index 0000000..3ebb50c
--- /dev/null
+++ b/source3/script/tests/test_dfree_command.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+#
+# Blackbox test for 'dfree command' and smbclient "l"
+# command disk free printout.
+#
+
+if [ $# -lt 6 ]; then
+ cat <<EOF
+Usage: test_dfree_command.sh SERVER DOMAIN USERNAME PASSWORD PREFIX SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER=$1
+DOMAIN=$2
+USERNAME=$3
+PASSWORD=$4
+PREFIX=$5
+smbclient=$6
+protocol=$7
+
+shift 7
+failed=0
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+test_smbclient_dfree()
+{
+ name="$1"
+ share="$2"
+ cmd="$3"
+ expected="$4"
+ shift
+ shift
+ shift
+ subunit_start_test "$name"
+ output=$($VALGRIND $smbclient //$SERVER/$share -c "$cmd" "$@" 2>&1)
+ status=$?
+ if [ x$status = x0 ]; then
+ received=$(echo "$output" | awk '/blocks of size/ {print $1, $5, $6}')
+ if [ "$expected" = "$received" ]; then
+ subunit_pass_test "$name"
+ return 0
+ else
+ echo "$output" | subunit_fail_test "$name"
+ return 1
+ fi
+ else
+ echo "$output" | subunit_fail_test "$name"
+ return $status
+ fi
+}
+
+if [ $protocol = "SMB3" ]; then
+ test_smbclient_dfree "Test dfree command share root SMB3" dfree "l" "2000 1024. 20" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+ test_smbclient_dfree "Test dfree command subdir1 SMB3" dfree "cd subdir1; l" "8000 1024. 80" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+ test_smbclient_dfree "Test dfree command subdir2 SMB3" dfree "cd subdir2; l" "32000 1024. 320" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+
+elif [ $protocol = "NT1" ]; then
+ test_smbclient_dfree "Test dfree command share root NT1" dfree "l" "2000 1024. 20" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=NT1 || failed=$(expr $failed + 1)
+ #SMB1 queries disk usage stat on the share's root, regardless of working directory
+ test_smbclient_dfree "Test dfree command subdir1 NT1" dfree "cd subdir1; l" "2000 1024. 20" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=NT1 || failed=$(expr $failed + 1)
+
+else
+ echo "unsupported protocol $protocol" | subunit_fail_test "Test dfree command"
+ failed=$(expr $failed + 1)
+fi
+exit $failed
diff --git a/source3/script/tests/test_dfree_quota.sh b/source3/script/tests/test_dfree_quota.sh
new file mode 100755
index 0000000..9151016
--- /dev/null
+++ b/source3/script/tests/test_dfree_quota.sh
@@ -0,0 +1,296 @@
+#!/bin/sh
+#
+# Blackbox test for disk-free, quota, and their interaction
+#
+
+if [ $# -lt 6 ]; then
+ cat <<EOF
+Usage: test_dfree_quota.sh SERVER DOMAIN USERNAME PASSWORD LOCAL_PATH SMBCLIENT SMBCQUOTAS SMBCACLS
+EOF
+ exit 1
+fi
+
+SERVER=$1
+DOMAIN=$2
+USERNAME=$3
+PASSWORD=$4
+ENVDIR=$(dirname $5)
+WORKDIR=$5/dfree
+smbclient=$6
+smbcquotas=$7
+smbcacls=$8
+protocol=$9
+shift 9
+failed=0
+
+CONFFILE=$ENVDIR/lib/dfq.conf
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+sighup_smbd()
+{
+ kill -HUP -$(cat $ENVDIR/pid/smbd.pid)
+}
+
+conf_lines()
+{
+ local uid
+ local gid
+ uid=$(id -u $USERNAME)
+ gid=$(id -g $USERNAME)
+ uid1=$(id -u user1)
+ uid2=$(id -u user2)
+ cat <<ABC
+conf1:df:block size = 512:disk free = 10:disk size = 20
+conf2:df:block size = 1024:disk free = 10:disk size = 20
+conf3:df:block size = 4096:disk free = 750:disk size = 281474976710656
+confq1:u$uid:block size = 4096:hard limit = 750:soft limit = 1000:cur blocks = 10
+confdfq1:df:block size = 4096:disk free = 10:disk size = 20
+confdfq1:u$uid:block size = 4096:hard limit = 750:soft limit = 1000:cur blocks = 10
+confdfq2:df:block size = 4096:disk free = 10:disk size = 20
+confdfq2:u$uid:block size = 4096:hard limit = 40:soft limit = 40:cur blocks = 37
+confdfq3:df:block size = 4096:disk free = 10:disk size = 80
+confdfq3:u$uid:block size = 4096:hard limit = 40:soft limit = 40:cur blocks = 0
+confdfq4:df:block size = 4096:disk free = 10:disk size = 80
+confdfq4:u$uid:block size = 4096:hard limit = 40:soft limit = 40:cur blocks = 37
+slimit:df:block size = 4096:disk free = 10:disk size = 80
+slimit:u$uid:block size = 4096:hard limit = 44:soft limit = 40:cur blocks = 42
+hlimit:df:block size = 4096:disk free = 10:disk size = 80
+hlimit:u$uid:block size = 4096:hard limit = 44:soft limit = 0:cur blocks = 45
+islimit:df:block size = 4096:disk free = 10:disk size = 80
+islimit:u$uid:block size = 4096:hard limit = 44:soft limit = 40:cur blocks = 37:inode soft limit = 30:inode hard limit = 35:cur inodes = 32
+ihlimit:df:block size = 4096:disk free = 10:disk size = 80
+ihlimit:u$uid:block size = 4096:hard limit = 44:soft limit = 40:cur blocks = 37:inode soft limit = 0:inode hard limit = 35:cur inodes = 36
+trygrp1:df:block size = 4096:disk free = 10:disk size = 80
+trygrp1:u$uid:block size = 4096:hard limit = 40:soft limit = 40:cur blocks = 41:err = 1
+trygrp1:g$gid:block size = 4096:hard limit = 60:soft limit = 60:cur blocks = 55
+trygrp2:df:block size = 4096:disk free = 10:disk size = 80
+trygrp2:u$uid:block size = 4096:hard limit = 0:soft limit = 0:cur blocks = 41
+trygrp2:g$gid:block size = 4096:hard limit = 60:soft limit = 60:cur blocks = 56
+blksize:df:block size = 512:disk free = 614400:disk size = 614400
+blksize:u$uid:block size = 1024:hard limit = 512000:soft limit = 0:cur blocks = 0
+notenforce:df:block size = 4096:disk free = 10:disk size = 80
+notenforce:u$uid:block size = 4096:hard limit = 40:soft limit = 40:cur blocks = 37
+notenforce:udflt:block size = 4096:qflags = 0
+nfs:df:block size = 4096:disk free = 10:disk size = 80
+nfs:u$uid:block size = 4096:hard limit = 40:soft limit = 40:cur blocks = 37
+nfs:udflt:nosys = 1
+confdfqp:df:block size = 4096:disk free = 10:disk size = 80
+confdfqp:u$uid1:block size = 4096:hard limit = 40:soft limit = 40:cur blocks = 36
+confdfqp:u$uid2:block size = 4096:hard limit = 41:soft limit = 41:cur blocks = 36
+sgid:stat:sgid = 98765
+sgid:u$uid:block size = 4096:hard limit = 0:soft limit = 0:cur blocks = 80
+sgid:g98765:block size = 4096:hard limit = 50:soft limit = 50:cur blocks = 40
+ABC
+}
+
+setup_1_conf()
+{
+ conf_name="$1"
+ subdir="$2"
+ absdir=$(readlink -f $WORKDIR/$subdir)
+ conf_lines | sed -rn "s/^$conf_name:(.*)/\1/p" | tr ":" "\n" |
+ awk -F '=' -v atdir=$absdir 'NF==1 {section=$1} NF==2 {sub(/\s*$/, "", $1); printf "\tfake_dfq:%s/%s/%s =%s\n", section, $1, atdir, $2}'
+}
+
+setup_conf()
+{
+ rm $CONFFILE
+ touch $CONFFILE
+
+ until [ -z "$1" ]; do
+ setup_1_conf $1 $2 >>$CONFFILE
+ shift
+ shift
+ done
+ sighup_smbd
+ #let it load...
+ sleep .5
+}
+
+test_smbclient_dfree()
+{
+ name="$1"
+ share="$2"
+ dir="$3"
+ confs="$4"
+ expected="$5"
+ shift
+ shift
+ shift
+ shift
+ subunit_start_test "$name"
+ setup_conf $confs
+ output=$($VALGRIND $smbclient //$SERVER/$share -c "cd $dir; l" "$@" 2>&1)
+ status=$?
+ if [ "$status" = "0" ]; then
+ received=$(echo "$output" | awk '/blocks of size/ {print $1, $5, $6}')
+ if [ "$expected" = "$received" ]; then
+ subunit_pass_test "$name"
+ return 0
+ else
+ echo "$output" | subunit_fail_test "$name"
+ return 1
+ fi
+ else
+ echo "$output" | subunit_fail_test "$name"
+ return $status
+ fi
+}
+
+# Issue two queries to different directories in one session to test
+# caching effects
+test_smbclient_dfree_2()
+{
+ name="$1"
+ share="$2"
+ dir1="$3"
+ dir2="$4"
+ confs="$5"
+ expected="$6"
+ subunit_start_test "$name"
+ setup_conf $confs
+ output=$($VALGRIND $smbclient //$SERVER/$share \
+ -c "cd $dir1; du; cd ..; cd $dir2 ; du" "$@" 2>&1)
+ status=$?
+ if [ "$status" = "0" ]; then
+ received=$(echo "$output" |
+ awk '/blocks of size/ {print $1, $5, $6}' |
+ tr '\n' ' ')
+ if [ "$expected" = "$received" ]; then
+ subunit_pass_test "$name"
+ return 0
+ else
+ echo "$output" | subunit_fail_test "$name"
+ return 1
+ fi
+ else
+ echo "$output" | subunit_fail_test "$name"
+ return $status
+ fi
+}
+
+test_smbcquotas()
+{
+ name="$1"
+ conf="$2"
+ user="$3"
+ expected="$4"
+ proto="$5"
+ shift
+ shift
+ shift
+ shift
+ shift
+ subunit_start_test "$name"
+ setup_conf "$conf" "."
+ if [ "$proto" = "smb2" ]; then
+ mproto="-m SMB2"
+ else
+ mproto="-m SMB1"
+ fi
+
+ output=$($VALGRIND $smbcquotas $mproto //$SERVER/dfq "$@" 2>/dev/null | tr '\\' '/')
+ status=$?
+ if [ "$status" = "0" ]; then
+ received=$(echo "$output" | awk "/$SERVER\\/$user/ {printf \"%s%s%s\", \$3, \$4, \$5}")
+ if [ "$expected" = "$received" ]; then
+ subunit_pass_test "$name"
+ return 0
+ else
+ echo "$output" | subunit_fail_test "$name"
+ return 1
+ fi
+ else
+ echo "$output" | subunit_fail_test "$name"
+ return $status
+ fi
+}
+
+if [ $protocol != "SMB3" ] && [ $protocol != "NT1" ]; then
+ echo "unsupported protocol $protocol" | subunit_fail_test "Test dfree quota"
+ failed=$(expr $failed + 1)
+fi
+
+if [ $protocol = "NT1" ]; then
+ setup_conf
+ #basic quota test (SMB1 only)
+ test_smbcquotas "Test user quota" confq1 $USERNAME "40960/4096000/3072000" "smb1" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=NT1 || failed=$(expr $failed + 1)
+ exit $failed
+fi
+
+#basic disk-free tests
+test_smbclient_dfree "Test dfree share root SMB3 no quota" dfq "." "conf1 ." "10 1024. 5" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+test_smbclient_dfree "Test dfree subdir SMB3 no quota" dfq "subdir1" "conf1 . conf2 subdir1" "20 1024. 10" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+test_smbclient_dfree "Test large disk" dfq "." "conf3 ." "1125899906842624 1024. 3000" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+#basic quota test (SMB2 only)
+test_smbcquotas "Test user quota" confq1 $USERNAME "40960/4096000/3072000" "smb2" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB2 || failed=$(expr $failed + 1)
+
+# Test dfree cache through queries in two different directories
+test_smbclient_dfree_2 "Test dfree cache" dfq_cache "." "subdir1" \
+ "conf1 . conf2 subdir1" "10 1024. 5 20 1024. 10 " \
+ -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 ||
+ failed=$(expr $failed + 1)
+
+#quota limit > disk size, remaining quota > disk free
+test_smbclient_dfree "Test dfree share root df vs quota case 1" dfq "." "confdfq1 ." "80 1024. 40" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+#quota limit > disk size, remaining quota < disk free
+test_smbclient_dfree "Test dfree share root df vs quota case 2" dfq "." "confdfq2 ." "80 1024. 12" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+#quota limit < disk size, remaining quota > disk free
+test_smbclient_dfree "Test dfree share root df vs quota case 3" dfq "." "confdfq3 ." "160 1024. 40" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+#quota limit < disk size, remaining quota < disk free
+test_smbclient_dfree "Test dfree share root df vs quota case 4" dfq "." "confdfq4 ." "160 1024. 12" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+test_smbclient_dfree "Test dfree subdir df vs quota case 4" dfq "subdir1" "confdfq4 subdir1" "160 1024. 12" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+
+#quota-->disk free special cases
+test_smbclient_dfree "Test quota->dfree soft limit" dfq "subdir1" "slimit subdir1" "168 1024. 0" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+test_smbclient_dfree "Test quota->dfree hard limit" dfq "subdir1" "hlimit subdir1" "180 1024. 0" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+test_smbclient_dfree "Test quota->dfree inode soft limit" dfq "subdir1" "islimit subdir1" "148 1024. 0" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+test_smbclient_dfree "Test quota->dfree inode hard limit" dfq "subdir1" "ihlimit subdir1" "148 1024. 0" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+test_smbclient_dfree "Test quota->dfree err try group" dfq "subdir1" "trygrp1 subdir1" "240 1024. 20" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+test_smbclient_dfree "Test quota->dfree no-quota try group" dfq "subdir1" "trygrp2 subdir1" "240 1024. 16" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+
+# sgid on directory
+test_smbclient_dfree "Test quota on sgid directory" dfq "subdir1" \
+ "sgid subdir1" "200 1024. 40" -U$USERNAME%$PASSWORD \
+ --option=clientmaxprotocol=SMB3 ||
+ failed=$(expr $failed + 1)
+
+#block size different in quota and df systems
+test_smbclient_dfree "Test quota->dfree different block size" dfq "subdir1" "blksize subdir1" "307200 1024. 307200" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+
+#quota configured but not enforced
+test_smbclient_dfree "Test dfree share root quota not enforced" dfq "." "notenforce ." "320 1024. 40" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+
+#FS quota not implemented (NFS case)
+test_smbclient_dfree "Test dfree share root FS quota not implemented" dfq "." "nfs ." "160 1024. 12" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+
+#test for dfree when owner is inherited
+#setup two folders with different owners
+rm -rf $WORKDIR/subdir3/*
+for d in / subdir3; do
+ $VALGRIND $smbcacls -U$USERNAME%$PASSWORD -D "ACL:$SERVER\user1:ALLOWED/0x0/FULL" //$SERVER/dfq $d >/dev/null 2>&1
+ $VALGRIND $smbcacls -U$USERNAME%$PASSWORD -a "ACL:$SERVER\user1:ALLOWED/0x0/FULL" //$SERVER/dfq $d || failed=$(expr $failed + 1)
+ $VALGRIND $smbcacls -U$USERNAME%$PASSWORD -D "ACL:$SERVER\user2:ALLOWED/0x0/FULL" //$SERVER/dfq $d >/dev/null 2>&1
+ $VALGRIND $smbcacls -U$USERNAME%$PASSWORD -a "ACL:$SERVER\user2:ALLOWED/0x0/FULL" //$SERVER/dfq $d || failed=$(expr $failed + 1)
+done
+
+$VALGRIND $smbclient //$SERVER/dfq -c "cd subdir3; mkdir user1" -Uuser1%$PASSWORD --option=clientmaxprotocol=SMB3 >/dev/null 2>&1 || failed=$(expr $failed + 1)
+$VALGRIND $smbclient //$SERVER/dfq -c "cd subdir3; mkdir user2" -Uuser2%$PASSWORD --option=clientmaxprotocol=SMB3 >/dev/null 2>&1 || failed=$(expr $failed + 1)
+#test quotas
+test_smbclient_dfree "Test dfree without inherit owner - user1 at user1" \
+ dfq "subdir3/user1" "confdfqp subdir3/user1 confdfqp subdir3/user2" "160 1024. 16" \
+ -Uuser1%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+test_smbclient_dfree "Test dfree without inherit owner - user1 at user2" \
+ dfq "subdir3/user2" "confdfqp subdir3/user1 confdfqp subdir3/user2" "160 1024. 16" \
+ -Uuser1%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+test_smbclient_dfree "Test dfree with inherit owner - user1 at user1" \
+ dfq_owner "subdir3/user1" "confdfqp subdir3/user1 confdfqp subdir3/user2" "160 1024. 16" \
+ -Uuser1%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+test_smbclient_dfree "Test dfree with inherit owner - user1 at user2" \
+ dfq_owner "subdir3/user2" "confdfqp subdir3/user1 confdfqp subdir3/user2" "164 1024. 20" \
+ -Uuser1%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=$(expr $failed + 1)
+
+setup_conf
+exit $failed
diff --git a/source3/script/tests/test_dropbox.sh b/source3/script/tests/test_dropbox.sh
new file mode 100755
index 0000000..a920c27
--- /dev/null
+++ b/source3/script/tests/test_dropbox.sh
@@ -0,0 +1,88 @@
+#!/bin/sh
+#
+# Blackbox test for valid users.
+#
+
+if [ $# -lt 7 ]; then
+ cat <<EOF
+Usage: $0 SERVER DOMAIN USERNAME PASSWORD PREFIX TARGET_ENV SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER=${1}
+DOMAIN=${2}
+USERNAME=${3}
+PASSWORD=${4}
+PREFIX=${5}
+TARGET_ENV=${6}
+SMBCLIENT=${7}
+shift 7
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+ADDARGS="$@"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+# Test listing a share with valid users succeeds
+test_dropbox()
+{
+ local filename="wurst.$$"
+ local filename_path="$PREFIX/$filename"
+ local dropbox_path="$PREFIX/$TARGET_ENV/share/$1/dirmode733"
+
+ local tmpfile=$PREFIX/smbclient.in.$$
+
+ echo "wurstbar" >$filename_path
+
+ cat >$tmpfile <<EOF
+lcd $PREFIX
+put $filename dirmode733\\$filename
+quit
+EOF
+
+ # Create dropbox directory and set permissions
+ mkdir -p $dropbox_path
+ chmod 0333 $dropbox_path
+
+ local cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT //$SERVER/$1 -U$USERNAME%$PASSWORD $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+
+ # Reset dropbox permissions
+ chmod 0755 $dropbox_path
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "Failed accessing share $ret"
+ echo "$out"
+
+ return 1
+ fi
+ rm -f $filename_path
+
+ dropped_file="$dropbox_path/$filename"
+ if [ ! -r "$dropped_file" ]; then
+ echo "Failed to drop file $filename"
+ echo "$out"
+ return 1
+ fi
+
+ content=$(cat $dropped_file)
+ if [ "$content" != "wurstbar" ]; then
+ echo "Invalid file content: $content"
+ echo "$out"
+ return 1
+ fi
+
+ return 0
+}
+
+testit "dropbox dirmode 0733" \
+ test_dropbox dropbox ||
+ failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source3/script/tests/test_durable_handle_reconnect.sh b/source3/script/tests/test_durable_handle_reconnect.sh
new file mode 100755
index 0000000..0ab3297
--- /dev/null
+++ b/source3/script/tests/test_durable_handle_reconnect.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# Test Durable Handle reconnect with injected delay in the disconnect.
+#
+# Copyright (C) 2018 Ralph Boehme
+
+. $(dirname $0)/../../../testprogs/blackbox/subunit.sh
+failed=0
+
+cd $SELFTEST_TMPDIR || exit 1
+
+delay_inject_conf=$(dirname $SMB_CONF_PATH)/delay_inject.conf
+
+echo 'delay_inject:fntimes = 5000' >$delay_inject_conf
+
+testit "durable_v2_delay.durable_v2_reconnect_delay" $VALGRIND \
+ $BINDIR/smbtorture //$SERVER_IP/delay_inject \
+ -U$USERNAME%$PASSWORD \
+ smb2.durable-v2-delay.durable_v2_reconnect_delay ||
+ failed=$(expr $failed + 1)
+
+SMBD_LOG_FILES="$SMBD_TEST_LOG"
+if [ $SMBD_DONT_LOG_STDOUT -eq 1 ]; then
+ _SMBD_LOG_FILE=$(dirname $SMBD_TEST_LOG)/logs/log.smbd
+ SMBD_LOG_FILES="$SMBD_LOG_FILES $_SMBD_LOG_FILE"
+fi
+
+testit "durable_v2_delay.durable_v2_reconnect_delay_msec" $VALGRIND \
+ $BINDIR/smbtorture //$SERVER_IP/durable \
+ -U$USERNAME%$PASSWORD \
+ smb2.durable-v2-delay.durable_v2_reconnect_delay_msec ||
+ failed=$(expr $failed + 1)
+
+rm $delay_inject_conf
+
+testok $0 $failed
diff --git a/source3/script/tests/test_failure.sh b/source3/script/tests/test_failure.sh
new file mode 100755
index 0000000..7a2c9ae
--- /dev/null
+++ b/source3/script/tests/test_failure.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+# Blackbox test that should fail one of three subtests.
+#
+# Copyright (C) 2011 Michael Adam <obnox@samba.org>
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+test_failure()
+{
+ false
+}
+
+test_success()
+{
+ true
+}
+
+testit "success" \
+ test_success ||
+ failed=$(expr $failed + 1)
+
+testit "failure" \
+ test_failure ||
+ failed=$(expr $failed + 1)
+
+testit "success" \
+ test_success ||
+ failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_fakedircreatetimes.sh b/source3/script/tests/test_fakedircreatetimes.sh
new file mode 100755
index 0000000..4ce2bcf
--- /dev/null
+++ b/source3/script/tests/test_fakedircreatetimes.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+
+if [ $# -lt 7 ]; then
+ cat <<EOF
+Usage: test_fakedircreatetimes.sh SERVER SERVER_IP USERNAME PASSWORD LOCAL_PATH PREFIX SMBCLIENT ADDARGS
+EOF
+ exit 1
+fi
+
+SERVER="${1}"
+SERVER_IP="${2}"
+USERNAME="${3}"
+PASSWORD="${4}"
+LOCAL_PATH="${5}"
+PREFIX="${6}"
+SMBCLIENT="${7}"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+shift 7
+ADDARGS="$*"
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir"/subunit.sh
+
+failed=0
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+# Define the test environment/filenames.
+#
+share_test_dir="$LOCAL_PATH"
+
+
+test_fakedircreatetimes()
+{
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/recycle -I$SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ cmd="LC_ALL=C TZ=UTC CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/fakedircreatetimes -I$SERVER_IP $ADDARGS -c 'allinfo \\'"
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+
+ ret=$?
+
+ if [ $ret != 0 ]; then
+ printf "%s\n" "$out"
+ printf "failed recycle smbclient run with error %s\n" "$ret"
+ return 1
+ fi
+
+ echo "$out" | grep -q "create_time:.*1979 UTC" && {
+ return 0
+ }
+
+ echo "ERROR: create_time does not match 1979 UTC:"
+ echo "$out"
+ return 1
+}
+
+
+testit "fakedircreatetimes" \
+ test_fakedircreatetimes ||
+ failed=$((failed + 1))
+
+
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_fifo.sh b/source3/script/tests/test_fifo.sh
new file mode 100755
index 0000000..199b0b4
--- /dev/null
+++ b/source3/script/tests/test_fifo.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+#
+# Check smbclient can list a directory containing a fifo.
+#
+
+if [ $# -lt 7 ]; then
+ cat <<EOF
+Usage: $0 SERVER DOMAIN USERNAME PASSWORD PREFIX TARGET_ENV SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER=${1}
+DOMAIN=${2}
+USERNAME=${3}
+PASSWORD=${4}
+PREFIX=${5}
+TARGET_ENV=${6}
+SMBCLIENT=${7}
+shift 7
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+ADDARGS="$@"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+# Test that listing a share with a directory containing a fifo succeeds.
+#
+# BUG: https://bugzilla.samba.org/show_bug.cgi?id=14816
+#
+test_fifo()
+{
+ local fifo_dir_path="$PREFIX/$TARGET_ENV/share/fifodir"
+ local fifo_path="$fifo_dir_path/fifo_name"
+
+ local tmpfile=$PREFIX/smbclient.in.$$
+
+ cat >$tmpfile <<EOF
+cd fifodir
+ls
+quit
+EOF
+
+ # Create fifo directory.
+ mkdir -p $fifo_dir_path
+ # Create fifo underneath.
+ mkfifo $fifo_path
+
+ local cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT //$SERVER/$1 -U$USERNAME%$PASSWORD $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+
+ # Remove fifo and containing dir.
+ rm $fifo_path
+ rmdir $fifo_dir_path
+ rm -f $tmpfile
+
+ # Check for smbclient error.
+ if [ $ret != 0 ]; then
+ echo "Failed accessing share containing dir with fifo $ret"
+ echo "$out"
+ return 1
+ fi
+
+ # Check for smbclient timeout (server hung).
+ echo "$out" | grep 'NT_STATUS_'
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ # Client was disconnected as server timed out.
+ echo "$out"
+ return 1
+ fi
+
+ return 0
+}
+
+testit "list directory containing a fifo" \
+ test_fifo tmp || failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source3/script/tests/test_force_close_share.sh b/source3/script/tests/test_force_close_share.sh
new file mode 100755
index 0000000..c9f943a
--- /dev/null
+++ b/source3/script/tests/test_force_close_share.sh
@@ -0,0 +1,115 @@
+#!/usr/bin/env bash
+#
+# Test smbcontrol close-share command.
+#
+# Copyright (C) 2020 Volker Lendecke
+# Copyright (C) 2020 Jeremy Allison
+#
+# Note this is designed to be run against
+# the aio_delay_inject share which is preconfigured
+# with 2 second delays on pread/pwrite.
+
+if [ $# -lt 6 ]; then
+ echo Usage: $0 SERVERCONFFILE SMBCLIENT SMBCONTROL IP aio_delay_inject_sharename PREFIX
+ exit 1
+fi
+
+CONFIGURATION=$1
+smbclient=$2
+SMBCONTROL=$3
+SERVER=$4
+SHARE=$5
+PREFIX=$6
+shift 6
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+. $incdir/common_test_fns.inc
+
+failed=0
+
+mkdir -p $PREFIX/private
+
+FIFO_STDIN="$PREFIX/smbclient-stdin"
+FIFO_STDOUT="$PREFIX/smbclient-stdout"
+FIFO_STDERR="$PREFIX/smbclient-stderr"
+TESTFILE="$PREFIX/testfile"
+
+rm -f $FIFO_STDIN $FIFO_STDOUT $FIFO_STDERR $TESTFILE 2>/dev/null
+
+# Create the smbclient communication pipes.
+mkfifo $FIFO_STDIN $FIFO_STDOUT $FIFO_STDERR
+if [ $? -ne 0 ]; then
+ echo "Failed to create fifos"
+ exit 1
+fi
+
+# Create a large-ish testfile
+head -c 100MB /dev/zero >$TESTFILE
+
+CLI_FORCE_INTERACTIVE=1
+export CLI_FORCE_INTERACTIVE
+
+${smbclient} //${SERVER}/${SHARE} ${CONFIGURATION} -U${USER}%${PASSWORD} \
+ <$FIFO_STDIN >$FIFO_STDOUT 2>$FIFO_STDERR &
+CLIENT_PID=$!
+
+count=0
+while [ 1 ]; do
+ if [ $count -ge 20 ]; then
+ echo "Failed to start smbclient"
+ exit 1
+ fi
+ kill -0 $CLIENT_PID
+ if [ $? -eq 0 ]; then
+ break
+ fi
+ sleep 0.5
+ count=$((count + 1))
+done
+
+exec 100>$FIFO_STDIN 101<$FIFO_STDOUT 102<$FIFO_STDERR
+
+# consume the smbclient startup messages
+head -n 1 <&101
+
+# Ensure we're putting a fresh file.
+echo "lcd $(dirname $TESTFILE)" >&100
+echo "del testfile" >&100
+echo "put testfile" >&100
+
+sleep 0.2
+
+# Close the aio_delay_inject share whilst we have outstanding writes.
+
+testit "smbcontrol" ${SMBCONTROL} ${CONFIGURATION} smbd close-share ${SHARE} ||
+ failed=$(expr $failed + 1)
+
+sleep 0.5
+
+# If we get one or more NT_STATUS_NETWORK_NAME_DELETED
+# or NT_STATUS_INVALID_HANDLE on stderr from the writes we
+# know the server stayed up and didn't crash when the
+# close-share removed the share.
+#
+# BUG: https://bugzilla.samba.org/show_bug.cgi?id=14301
+#
+COUNT=$(head -n 2 <&102 |
+ grep -e NT_STATUS_NETWORK_NAME_DELETED -e NT_STATUS_INVALID_HANDLE |
+ wc -l)
+
+testit "Verify close-share did cancel the file put" \
+ test $COUNT -ge 1 || failed=$(expr $failed + 1)
+
+kill ${CLIENT_PID}
+
+# Remove the testfile from the server
+test_smbclient "remove_testfile" \
+ 'del testfile; quit' //${SERVER}/${SHARE} -U${USER}%${PASSWORD} ||
+ failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_force_create_mode.sh b/source3/script/tests/test_force_create_mode.sh
new file mode 100755
index 0000000..289f219
--- /dev/null
+++ b/source3/script/tests/test_force_create_mode.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+#
+# Blackbox test for 'force create mode'
+#
+
+if [ $# -lt 7 ]; then
+ cat <<EOF
+Usage: $0 SERVER DOMAIN USERNAME PASSWORD PREFIX TARGET_ENV SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER=${1}
+DOMAIN=${2}
+USERNAME=${3}
+PASSWORD=${4}
+PREFIX=${5}
+TARGET_ENV=${6}
+SMBCLIENT=${7}
+shift 7
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+ADDARGS="$@"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+test_force_create_mode()
+{
+ local filename="wurst.$$"
+ local filename_path="$PREFIX/$filename"
+
+ local tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+
+ echo wurstbar >$filename_path
+
+ cat >$tmpfile <<EOF
+lcd $PREFIX
+put $filename
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/$1 $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "Failed to connect - error: $ret"
+ return 1
+ fi
+ rm -f $filename_path
+
+ share_filename="$PREFIX/$TARGET_ENV/share/$filename"
+ file_perms=$(stat --format=%a $share_filename)
+ if [ "$file_perms" != "664" ]; then
+ echo "Invalid file permissions: $file_perms"
+ return 1
+ fi
+
+ rm -f $share_filename
+
+ return 0
+}
+
+testit "test_mode=0664" \
+ test_force_create_mode create_mode_664 ||
+ failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source3/script/tests/test_force_group_change.sh b/source3/script/tests/test_force_group_change.sh
new file mode 100755
index 0000000..bf82903
--- /dev/null
+++ b/source3/script/tests/test_force_group_change.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+# Copyright (c) Jeremy Allison <jra@samba.org>
+# License: GPLv3
+# Regression test for BUG:https://bugzilla.samba.org/show_bug.cgi?id=13690
+
+if [ $# -lt 6 ]; then
+ echo "Usage: test_force_group_change.sh SERVER USERNAME PASSWORD LOCAL_PATH SMBCLIENT SMBCONTROL"
+ exit 1
+fi
+
+SERVER="${1}"
+USERNAME="${2}"
+PASSWORD="${3}"
+LOCAL_PATH="${4}"
+SMBCLIENT="${5}"
+SMBCONTROL="${6}"
+shift 6
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+test_force_group_change()
+{
+ #
+ # A SMB_CONF variable passed in here is the client smb.conf.
+ # We need to convert to the server.conf file from
+ # the LOCAL_PATH variable.
+ #
+ SERVER_CONFIG=$(dirname $LOCAL_PATH)/lib/server.conf
+ SERVER_CONFIG_SAVE=${SERVER_CONFIG}.bak
+ SERVER_CONFIG_NEW=${SERVER_CONFIG}.new
+ cp $SERVER_CONFIG $SERVER_CONFIG_SAVE
+
+ sed -e 's/#\tforce group = everyone/\tforce group = everyone/' <${SERVER_CONFIG} >${SERVER_CONFIG_NEW}
+
+ tmpfile=$PREFIX/smbclient_force_group_change_commands
+ cat >$tmpfile <<EOF
+ls
+!cp ${SERVER_CONFIG_NEW} ${SERVER_CONFIG}
+!${SMBCONTROL} --configfile=${SERVER_CONFIG} all reload-config
+ls
+!cp ${SERVER_CONFIG_SAVE} ${SERVER_CONFIG}
+!${SMBCONTROL} --configfile=${SERVER_CONFIG} all reload-config
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/force_group_test $CONFIGURATION < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+ rm -f $SERVER_CONFIG_SAVE
+ rm -f $SERVER_CONFIG_NEW
+
+ echo "$out" | grep 'NT_STATUS_CONNECTION_DISCONNECTED'
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ # Client was disconnected as server crashed.
+ echo "$out"
+ return 1
+ fi
+
+ return 0
+}
+
+testit "test force group change" \
+ test_force_group_change ||
+ failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_force_user_unlink.sh b/source3/script/tests/test_force_user_unlink.sh
new file mode 100755
index 0000000..c67b28f
--- /dev/null
+++ b/source3/script/tests/test_force_user_unlink.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# Test unlink on share with "force user"
+#
+# Copyright (C) 2021 Ralph Boehme
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+. $incdir/common_test_fns.inc
+
+smbclient="$BINDIR/smbclient"
+error_inject_conf=$(dirname ${SMB_CONF_PATH})/error_inject.conf
+failed=0
+
+test_forced_user_can_delete()
+{
+ out=$($smbclient -U $DOMAIN/$USERNAME%$PASSWORD //$SERVER_IP/force_user_error_inject -c "rm dir/file")
+ if [ $? -ne 0 ]; then
+ echo $out
+ return 1
+ fi
+ tmp=$(echo $out | grep NT_STATUS_)
+ if [ $? -eq 0 ]; then
+ return 1
+ fi
+ return 0
+}
+
+echo "error_inject:unlinkat = EACCES" >${error_inject_conf}
+
+$smbclient -U $DOMAIN/$USERNAME%$PASSWORD //$SERVER_IP/force_user_error_inject -c "mkdir dir" || failed=$(expr $failed + 1)
+$smbclient -U $DOMAIN/$USERNAME%$PASSWORD //$SERVER_IP/force_user_error_inject -c "put WHATSNEW.txt dir/file" || failed=$(expr $failed + 1)
+
+testit "test_forced_user_can_delete" test_forced_user_can_delete || failed=$(expr $failed + 1)
+
+rm ${error_inject_conf}
+
+# Clean up after ourselves.
+$smbclient -U $DOMAIN/$USERNAME%$PASSWORD //$SERVER_IP/force_user_error_inject -c "del dir/file; rmdir dir"
+
+testok $0 $failed
diff --git a/source3/script/tests/test_forceuser_validusers.sh b/source3/script/tests/test_forceuser_validusers.sh
new file mode 100755
index 0000000..11c1a5b
--- /dev/null
+++ b/source3/script/tests/test_forceuser_validusers.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+#
+# Blackbox test for share with force user settings
+#
+
+if [ $# -lt 6 ]; then
+ cat <<EOF
+Usage: test_forceuser_validusers.sh SERVER DOMAIN USERNAME PASSWORD LOCAL_PATH SMBCLIENT <smbclient arguments>
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+DOMAIN="$2"
+USERNAME="force_user"
+PASSWORD="$4"
+LOCAL_PATH="$5"
+SMBCLIENT="$6"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+shift 6
+ADDARGS="$*"
+failed=0
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+cd $SELFTEST_TMPDIR || exit 1
+
+run_cmd_nooutput()
+{
+ CMD="$1"
+
+ out=$(eval ${CMD} >TESTOUT 2>&1)
+ if [ $? != 0 ]; then
+ cat TESTOUT
+ rm -f TESTOUT
+ echo "command failed"
+ false
+ return
+ fi
+
+ rm -f TESTOUT
+ true
+ return
+}
+
+test_force_user_valid_users()
+{
+ SMB_SHARE="force_user_valid_users"
+ run_cmd_nooutput "${SMBCLIENT} //${SERVER}/${SMB_SHARE} -U$USERNAME%$PASSWORD -c 'ls'"
+}
+
+# Test
+testit "force user not works when combined with valid users" \
+ test_force_user_valid_users || failed=$(expr $failed + 1)
+
+# Cleanup
+
+# Results
+testok $0 $failed
diff --git a/source3/script/tests/test_fruit_resource_stream.sh b/source3/script/tests/test_fruit_resource_stream.sh
new file mode 100755
index 0000000..7e99ea3
--- /dev/null
+++ b/source3/script/tests/test_fruit_resource_stream.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+# this tests copying a file and then deleting it
+# to a share using fruit:resource = stream
+# BUG: https://bugzilla.samba.org/show_bug.cgi?id=15099
+
+if [ $# -lt 6 ]; then
+ cat <<EOF
+Usage: $0 SERVER SHARE USERNAME PASSWORD LOCAL_PATH SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER="${1}"
+SHARE="${2}"
+USERNAME="${3}"
+PASSWORD="${4}"
+LOCAL_PATH="${5}"
+SMBCLIENT="${6}"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir/subunit.sh"
+
+failed=0
+
+put_then_delete_file()
+{
+ $SMBCLIENT //"$SERVER"/"$SHARE" -U"$USERNAME"%"$PASSWORD" -c "lcd $LOCAL_PATH; put src dst; rm dst" >/dev/null 2>&1
+}
+
+rm -f "$LOCAL_PATH/src"
+rm -f "$LOCAL_PATH/dst"
+touch "$LOCAL_PATH/src"
+
+testit "resource_stream" put_then_delete_file || failed=$((failed + 1))
+
+rm -f "$LOCAL_PATH/src"
+rm -f "$LOCAL_PATH/dst"
+
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_give_owner.sh b/source3/script/tests/test_give_owner.sh
new file mode 100755
index 0000000..9d00918
--- /dev/null
+++ b/source3/script/tests/test_give_owner.sh
@@ -0,0 +1,147 @@
+#!/bin/sh
+#
+# this verifies that SEC_STD_WRITE_OWNER only effectively grants take-ownership
+# permissions but NOT give-ownership.
+#
+
+if [ $# -lt 9 ]; then
+ echo "Usage: $0 SERVER SERVER_IP USERNAME PASSWORD PREFIX SMBCLIENT SMBCACLS NET SHARE"
+ exit 1
+fi
+
+SERVER="$1"
+SERVER_IP="$2"
+USERNAME="$3"
+PASSWORD="$4"
+PREFIX="$5"
+SMBCLIENT="$6"
+SMBCACLS="$7"
+NET="$8"
+SHARE="$9"
+
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+SMBCACLS="$VALGRIND ${SMBCACLS}"
+NET="$VALGRIND ${NET}"
+failed=0
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+setup_testfile()
+{
+ local share=$1
+ local fname=$2
+ touch $PREFIX/$fname
+ $SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "rm $fname"
+ $SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "ls" | grep "$fname" && return 1
+ $SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "lcd $PREFIX; put $fname" || return 1
+}
+
+remove_testfile()
+{
+ local share=$1
+ local fname=$2
+ $SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "rm $fname"
+}
+
+set_win_owner()
+{
+ local share=$1
+ local fname=$2
+ local owner=$3
+ echo "$SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD -C '$owner'"
+ $SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD -C "$owner" || return 1
+}
+
+win_owner_is()
+{
+ local share=$1
+ local fname=$2
+ local expected_owner=$3
+ local actual_owner
+
+ echo "$SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD"
+ $SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD
+ actual_owner=$($SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD | sed -rn 's/^OWNER:(.*)/\1/p')
+ echo "actual_owner = $actual_owner"
+ if ! test "x$actual_owner" = "x$expected_owner"; then
+ echo "Actual owner of $share/$fname is [$actual_owner] expected [$expected_owner]"
+ return 1
+ fi
+ return 0
+}
+
+add_ace()
+{
+ local share=$1
+ local fname=$2
+ local ace=$3
+
+ local_ace=$(printf '%s' "$ace" | sed 's|\\|/|')
+
+ # avoid duplicate
+ out=$($SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD)
+ if [ $? -ne 0 ]; then
+ echo "get acl failed"
+ echo "$out"
+ return 1
+ fi
+ echo "Original ACL"
+ echo $out
+ echo "$out" | grep "$local_ace" && return 0
+
+ # add it
+ $SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD -a "$ace"
+ if [ $? -ne 0 ]; then
+ echo "add acl failed"
+ return 1
+ fi
+
+ # check it's there
+ out=$($SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD)
+ if [ $? -ne 0 ]; then
+ echo "get new acl failed"
+ echo "$out"
+ return 1
+ fi
+ echo "New ACL"
+ echo $out
+ echo "Checking if new ACL has \"$local_ace\""
+ echo "$out" | grep "$local_ace" || return 1
+ echo "ok"
+}
+
+chown_give_fails()
+{
+ local share=$1
+ local fname=$2
+ local user=$3
+ local expected_error=$4
+
+ # this must fail
+ out=$($SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD -C "$user") && return 1
+ # it failed, now check it returned the expected error code
+ echo "$out" | grep $expected_error || return 1
+}
+
+# Create a testfile
+testit "create testfile" setup_testfile $SHARE afile || failed=$(expr $failed + 1)
+testit "verify owner" win_owner_is $SHARE afile "$SERVER/$USERNAME" || failed=$(expr $failed + 1)
+
+# Grant SeRestorePrivilege to the user and full rights on the file
+testit "grant SeRestorePrivilege" $NET rpc rights grant $USERNAME SeRestorePrivilege -U $USERNAME%$PASSWORD -I $SERVER_IP || failed=$(expr $failed + 1)
+testit "grant full rights" add_ace $SHARE afile "ACL:$SERVER\\$USERNAME:ALLOWED/0x0/FULL" || failed=$(expr $failed + 1)
+
+# We have SeRestorePrivilege, so both give and take ownership must succeed
+testit "give owner with SeRestorePrivilege" set_win_owner $SHARE afile "$SERVER\user1" || failed=$(expr $failed + 1)
+testit "verify owner" win_owner_is $SHARE afile "$SERVER/user1" || failed=$(expr $failed + 1)
+testit "take owner" set_win_owner $SHARE afile "$SERVER\\$USERNAME" || failed=$(expr $failed + 1)
+testit "verify owner" win_owner_is $SHARE afile "$SERVER/$USERNAME" || failed=$(expr $failed + 1)
+
+# Revoke SeRestorePrivilege, give ownership must fail now with NT_STATUS_INVALID_OWNER
+testit "revoke SeRestorePrivilege" $NET rpc rights revoke $USERNAME SeRestorePrivilege -U $USERNAME%$PASSWORD -I $SERVER_IP || failed=$(expr $failed + 1)
+testit "give owner without SeRestorePrivilege" chown_give_fails $SHARE afile "$SERVER\user1" NT_STATUS_INVALID_OWNER || failed=$(expr $failed + 1)
+
+testit "delete testfile" remove_testfile $SHARE afile || failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source3/script/tests/test_groupmap.sh b/source3/script/tests/test_groupmap.sh
new file mode 100755
index 0000000..a1e9a08
--- /dev/null
+++ b/source3/script/tests/test_groupmap.sh
@@ -0,0 +1,217 @@
+#!/bin/sh
+# test groupmap code tridge@samba.org September 2006
+# note that this needs root access to add unix groups,
+# so this cannot be run on the build farm
+
+testone()
+{
+ echo $*
+ $VALGRIND bin/net groupmap $*
+}
+
+tstart()
+{
+ TBASE=$(date '+%s')
+}
+
+treport()
+{
+ TNOW=$(date '+%s')
+ echo "Took $(expr $TNOW - $TBASE) seconds"
+ TBASE=$TNOW
+}
+
+rm -f $PREFIX_ABS/var/locks/group_mapping.?db
+
+NLOCAL=12
+NGROUP=11
+NBUILTIN=10
+DOMSID=$(bin/net getlocalsid | awk '{print $6}')
+FORSID="S-1-2-3-4-5"
+
+echo "DOMSID $DOMSID"
+echo "FORSID $FORSID"
+
+tstart
+echo "Creating unix groups"
+for i in $(seq 1 1 $NLOCAL); do
+ unixgroup=testlocal$i
+ gid=$(expr 30000 + $i)
+ groupdel $unixgroup 2>/dev/null
+ groupadd -g $gid $unixgroup || exit 1
+done
+for i in $(seq 1 1 $NGROUP); do
+ unixgroup=testgrp$i
+ gid=$(expr 40000 + $i)
+ groupdel $unixgroup 2>/dev/null
+ groupadd -g $gid $unixgroup || exit 1
+done
+for i in $(seq 1 1 $NBUILTIN); do
+ unixgroup=testb$i
+ gid=$(expr 50000 + $i)
+ groupdel $unixgroup 2>/dev/null
+ groupadd -g $gid $unixgroup || exit 1
+done
+date
+
+treport
+
+echo "Creating local groups"
+for i in $(seq 1 1 $NLOCAL); do
+ unixgroup=testlocal$i
+ ntgroup=ntlgrp$i
+ rid=$(expr 10000 + $i)
+ testone add rid=$rid unixgroup=$unixgroup ntgroup=$ntgroup type=local || exit 1
+done
+
+echo "trying a duplicate add"
+testone add rid=10001 unixgroup=testlocal1 ntgroup=foo type=local && exit 1
+
+treport
+
+echo "Creating domain groups"
+for i in $(seq 1 1 $NGROUP); do
+ unixgroup=testgrp$i
+ ntgroup=ntgrp$i
+ rid=$(expr 20000 + $i)
+ testone add rid=$rid unixgroup=$unixgroup ntgroup=$ntgroup type=domain || exit 1
+done
+
+treport
+
+echo "Creating builtin groups"
+for i in $(seq 1 1 $NBUILTIN); do
+ unixgroup=testb$i
+ ntgroup=ntbgrp$i
+ rid=$(expr 30000 + $i)
+ testone add rid=$rid unixgroup=$unixgroup ntgroup=$ntgroup type=builtin || exit 1
+done
+
+treport
+
+echo "Adding domain groups to local groups"
+for i in $(seq 1 1 $NLOCAL); do
+ for j in $(seq 1 1 $i); do
+
+ lrid=$(expr 10000 + $i)
+ drid=$(expr 20000 + $j)
+
+ testone addmem $DOMSID-$lrid $DOMSID-$drid || exit 1
+ (testone listmem $DOMSID-$lrid | sort -r) || exit 1
+ done
+done
+
+echo "trying a duplicate addmem"
+testone addmem $DOMSID-10001 $DOMSID-20001 && exit 1
+
+echo "Adding foreign SIDs to local groups"
+for i in $(seq 1 1 $NLOCAL); do
+ for j in $(seq 1 1 $i); do
+
+ lrid=$(expr 10000 + $i)
+ frid=$(expr 70000 + $j)
+
+ testone addmem $DOMSID-$lrid $FORSID-$frid || exit 1
+ (testone listmem $DOMSID-$lrid | sort -r) || exit 1
+ done
+done
+
+echo "trying a duplicate foreign addmem"
+testone addmem $DOMSID-10001 $FORSID-70001 && exit 1
+
+treport
+
+echo "Listing local group memberships of domain groups"
+for i in $(seq 1 1 $NGROUP); do
+ rid=$(expr 20000 + $i)
+ (testone memberships $DOMSID-$rid | sort -r) || exit 1
+done
+
+echo "Trying memberships on bogus sid"
+testone memberships $DOMSID-999999 || exit 1
+
+treport
+
+testone list | sort
+
+echo "Deleting some domain groups"
+for i in $(seq 2 2 $NGROUP); do
+ drid=$(expr 20000 + $i)
+ testone delete sid=$DOMSID-$drid || exit 1
+done
+
+echo "Trying duplicate domain group delete"
+testone delete sid=$DOMSID-20002 && exit 1
+
+treport
+
+echo "Deleting some local groups"
+for i in $(seq 2 4 $NLOCAL); do
+ lrid=$(expr 10000 + $i)
+ testone delete sid=$DOMSID-$lrid || exit 1
+done
+
+echo "Trying duplicate local group delete"
+testone delete sid=$DOMSID-10002 && exit 1
+
+treport
+
+echo "Modifying some domain groups"
+for i in $(seq 3 2 $NGROUP); do
+ drid=$(expr 20000 + $i)
+ testone modify sid=$DOMSID-$drid comment="newcomment-$i" type=domain || exit 1
+done
+
+treport
+
+testone list | sort
+
+echo "Listing local group memberships"
+for i in $(seq 1 1 $NLOCAL); do
+ rid=$(expr 20000 + $i)
+ (testone memberships $DOMSID-$rid | sort -r) || exit 1
+done
+
+treport
+
+echo "Removing some domain groups from local groups"
+for i in $(seq 1 2 $NLOCAL); do
+ for j in $(seq 1 3 $i); do
+
+ lrid=$(expr 10000 + $i)
+ drid=$(expr 20000 + $j)
+
+ testone delmem $DOMSID-$lrid $DOMSID-$drid || exit 1
+ done
+done
+
+echo "Trying duplicate delmem"
+testone delmem $DOMSID-10001 $DOMSID-20001 && exit 1
+
+treport
+
+echo "Listing local group memberships"
+for i in $(seq 1 1 $NLOCAL); do
+ rid=$(expr 20000 + $i)
+ (testone memberships $DOMSID-$rid | sort -r) || exit 1
+done
+
+treport
+
+echo "Deleting unix groups"
+for i in $(seq 1 1 $NLOCAL); do
+ unixgroup=testlocal$i
+ groupdel $unixgroup 2>/dev/null
+done
+for i in $(seq 1 1 $NGROUP); do
+ unixgroup=testgrp$i
+ groupdel $unixgroup 2>/dev/null
+done
+for i in $(seq 1 1 $NBUILTIN); do
+ unixgroup=testb$i
+ groupdel $unixgroup 2>/dev/null
+done
+
+treport
+
+echo "ALL DONE"
diff --git a/source3/script/tests/test_guest_auth.sh b/source3/script/tests/test_guest_auth.sh
new file mode 100755
index 0000000..fc18114
--- /dev/null
+++ b/source3/script/tests/test_guest_auth.sh
@@ -0,0 +1,106 @@
+#!/bin/sh
+#
+# Test guest authentication
+#
+# Copyright (C) 2019 Ralph Boehme
+#
+
+if [ $# -lt 5 ]; then
+ cat <<EOF
+Usage: $0 SERVER SMBCLIENT SMBCONTROL NET CONFIGURATION
+EOF
+ exit 1
+fi
+
+SERVER=$1
+SMBCLIENT=$2
+SMBCONTROL=$3
+NET=$4
+CONFIGURATION=$5
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+SIDS=""
+
+prepare_empty_builtin_guests()
+{
+ TMP=$($NET $CONFIGURATION groupmap listmem S-1-5-32-546 2>&1)
+ bg_exists=$?
+ if [ $bg_exists != 0 ]; then
+ printf "Group map for BUILTIN\\Guests must exist for test\n"
+ return 1
+ fi
+
+ SIDS=$($NET $CONFIGURATION groupmap listmem S-1-5-32-546)
+ if [ $? != 0 ]; then
+ printf "$NET $CONFIGURATION groupmap listmem S-1-5-32-546 failed. Returned:\n"
+ printf "$SIDS\n"
+ return 1
+ fi
+ printf "Got S-1-5-32-546 members:\n$SIDS\n"
+
+ if [ "$SIDS" != "" ]; then
+ for SID in $SIDS; do
+ printf "Deleting member $SID from S-1-5-32-546\n"
+ $NET $CONFIGURATION groupmap delmem S-1-5-32-546 $SID || return 1
+ done
+ fi
+
+ return 0
+}
+
+add_local_guest_to_builtin_guests()
+{
+ if [ "$SIDS" != "" ]; then
+ for SID in $SIDS; do
+ printf "Adding $SID as member to S-1-5-32-546\n"
+ $NET $CONFIGURATION groupmap addmem S-1-5-32-546 $SID || return 1
+ done
+ fi
+}
+
+test_smbclient()
+{
+ $SMBCLIENT -U foo%bar //$SERVER/tmpguest -c exit
+ if [ $? != 0 ]; then
+ printf "smbclient failed\n"
+ return 1
+ fi
+ return 0
+}
+
+testit "smbclient_guest_at_startup" \
+ test_smbclient ||
+ failed=$(expr $failed + 1)
+
+printf "Prepare BUILTIN\\Guests group mapping without members\n"
+
+prepare_empty_builtin_guests || {
+ printf "Setting up BUILTIN\\Guests without members failed\n"
+ exit 1
+}
+
+$SMBCONTROL $CONFIGURATION smbd reload-config || {
+ printf "Reloading parent smbd guest info failed\n"
+ exit 1
+}
+
+testit "smbclient_guest_auth_without_members" \
+ test_smbclient ||
+ failed=$(expr $failed + 1)
+
+# restore config
+add_local_guest_to_builtin_guests
+
+$SMBCONTROL $CONFIGURATION smbd reload-config || {
+ printf "Reloading parent smbd guest info failed\n"
+ exit 1
+}
+
+testit "smbclient_works_after_restored_setup" \
+ test_smbclient ||
+ failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_homes.sh b/source3/script/tests/test_homes.sh
new file mode 100755
index 0000000..be8e9b2
--- /dev/null
+++ b/source3/script/tests/test_homes.sh
@@ -0,0 +1,136 @@
+#!/bin/sh
+
+# Copyright (c) Andreas Schneider <asn@samba.org>
+# License: GPLv3
+
+if [ $# -lt 7 ]; then
+ echo "Usage: test_homes.sh SERVER USERNAME PASSWORD LOCAL_PATH PREFIX SMBCLIENT CONFIGURATION"
+ exit 1
+fi
+
+SERVER="${1}"
+USERNAME="${2}"
+PASSWORD="${3}"
+LOCAL_PATH="${4}"
+PREFIX="${5}"
+SMBCLIENT="${6}"
+CONFIGURATION="${7}"
+shift 7
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+test_gooduser_home()
+{
+ tmpfile=$PREFIX/smbclient_homes_gooduser_commands
+ cat >$tmpfile <<EOF
+ls
+quit
+EOF
+
+ USERNAME=gooduser
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/$USERNAME $CONFIGURATION < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "failed to connect error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep 'Try "help" to get a list of possible commands.'
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo 'failed - should get: Try "help" to get a list of possible commands.'
+ return 1
+ fi
+
+ return 0
+}
+
+test_eviluser_home()
+{
+ tmpfile=$PREFIX/smbclient_homes_eviluser_commands
+ cat >$tmpfile <<EOF
+ls
+quit
+EOF
+
+ USERNAME=eviluser
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/$USERNAME $CONFIGURATION < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret -ne 1 ]; then
+ echo "$out"
+ echo "The server should reject connecting ret=$ret"
+ return 1
+ fi
+
+ echo "$out" | grep 'NT_STATUS_BAD_NETWORK_NAME'
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo 'failed - should get: NT_STATUS_BAD_NETWORK_NAME.'
+ return 1
+ fi
+
+ return 0
+}
+
+test_slashuser_home()
+{
+ tmpfile=$PREFIX/smbclient_homes_slashuser_commands
+ cat >$tmpfile <<EOF
+ls
+quit
+EOF
+
+ USERNAME=slashuser
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/$USERNAME $CONFIGURATION < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret -ne 1 ]; then
+ echo "$out"
+ echo "The server should reject connecting ret=$ret"
+ return 1
+ fi
+
+ echo "$out" | grep 'NT_STATUS_BAD_NETWORK_NAME'
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo 'failed - should get: NT_STATUS_BAD_NETWORK_NAME.'
+ return 1
+ fi
+
+ return 0
+}
+
+testit "test gooduser home" \
+ test_gooduser_home ||
+ failed=$(expr $failed + 1)
+
+testit "test eviluser home reject" \
+ test_eviluser_home ||
+ failed=$(expr $failed + 1)
+
+testit "test slashuser home reject" \
+ test_slashuser_home ||
+ failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_inherit_owner.sh b/source3/script/tests/test_inherit_owner.sh
new file mode 100755
index 0000000..aa61671
--- /dev/null
+++ b/source3/script/tests/test_inherit_owner.sh
@@ -0,0 +1,170 @@
+#!/bin/sh
+
+# this tests "inherit owner" config parameter
+# currently needs to run in SMB1 mode, because it uses UNIX
+# extensions to fetch the UNIX owner of a file.
+
+if [ $# -lt 10 ]; then
+ cat <<EOF
+Usage: $0 SERVER USERNAME PASSWORD PREFIX SMBCLIENT SMBCACLS NET SHARE INH_WIN INH_UNIX <additional args>
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+USERNAME="$2"
+PASSWORD="$3"
+PREFIX="$4"
+SMBCLIENT="$5"
+SMBCACLS="$6"
+NET="$7"
+SHARE="$8"
+INH_WIN="$9"
+INH_UNIX="${10}"
+shift 10
+ADDARGS="$*"
+SMBCLIENT="$VALGRIND ${SMBCLIENT} ${ADDARGS}"
+SMBCACLS="$VALGRIND ${SMBCACLS} ${ADDARGS}"
+NET="$VALGRIND ${NET}"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+create_file()
+{
+ local share=$1
+ local fname=$2
+ local rem_dirname=$(dirname $fname)
+ local bname=$(basename $fname)
+ touch $PREFIX/$bname
+ $SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "cd $rem_dirname; rm $bname" 2>/dev/null
+ $SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "cd $rem_dirname; allinfo $bname" 2>/dev/null | grep "NT_STATUS_OBJECT_NAME_NOT_FOUND" || exit 1
+ $SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "lcd $PREFIX; cd $rem_dirname; put $bname" 2>/dev/null || exit 1
+}
+
+create_dir()
+{
+ local share=$1
+ local dname=$2
+ local rem_dirname=$(dirname $dname)
+ local bname=$(basename $dname)
+ $SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "cd $rem_dirname; rmdir $bname" 2>/dev/null
+ $SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "cd $rem_dirname; allinfo $bname" 2>/dev/null | grep "NT_STATUS_OBJECT_NAME_NOT_FOUND" || exit 1
+ $SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "cd $rem_dirname; mkdir $bname" 2>/dev/null || exit 1
+}
+
+cleanup_file()
+{
+ local share=$1
+ local fname=$2
+ local rem_dirname=$(dirname $fname)
+ local bname=$(basename $fname)
+ $SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "cd $rem_dirname; rm $bname" 2>/dev/null || exit 1
+}
+
+cleanup_dir()
+{
+ local share=$1
+ local dname=$2
+ local rem_dirname=$(dirname $dname)
+ local bname=$(basename $dname)
+ $SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "cd $rem_dirname; rmdir $bname" 2>/dev/null || exit 1
+}
+
+set_win_owner()
+{
+ local share=$1
+ local fname=$2
+ local owner=$3
+ $SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD -C $owner 2>/dev/null || exit 1
+}
+
+unix_owner_id_is()
+{
+ local share=$1
+ local fname=$2
+ local expected_id=$3
+ local actual_id
+ actual_id=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null | sed -rn 's/^# owner: (.*)/\1/p')
+ if ! test "x$actual_id" = "x$expected_id"; then
+ echo "Actual uid of $share/$fname is [$actual_id] expected [$expected_id]"
+ exit 1
+ fi
+}
+
+get_unix_id()
+{
+ local user=$1
+ local ent
+ ent=$(getent passwd $user) || exit 1
+ echo "$ent" | awk -F: '{print $3}'
+}
+
+win_owner_is()
+{
+ local share=$1
+ local fname=$2
+ local expected_owner=$3
+ local actual_owner
+ actual_owner=$($SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD 2>/dev/null | sed -rn 's/^OWNER:(.*)/\1/p')
+ if ! test "x$actual_owner" = "x$expected_owner"; then
+ echo "Actual owner of $share/$fname is [$actual_owner] expected [$expected_owner]"
+ exit 1
+ fi
+}
+
+default_uid=$(get_unix_id $USERNAME)
+alt_uid=$(get_unix_id force_user)
+
+if [ "$INH_WIN" = "0" ] && [ "$INH_UNIX" = "0" ]; then
+ #default - file owned by creator, change-owner modifies both
+ WIN_OWNER_AFTER_CREATE="$SERVER/$USERNAME"
+ UNIX_OWNER_AFTER_CREATE=$(get_unix_id $USERNAME)
+ WIN_OWNER_AFTER_CHOWN="$SERVER/smbget_user"
+ UNIX_OWNER_AFTER_CHOWN=$(get_unix_id smbget_user)
+ TEST_LABEL="default"
+elif [ "$INH_WIN" = "1" ] && [ "$INH_UNIX" = "1" ]; then
+ #inherit owner=windows and unix - file owned by parent
+ #owner, change-owner modifies both
+ WIN_OWNER_AFTER_CREATE="$SERVER/force_user"
+ UNIX_OWNER_AFTER_CREATE=$(get_unix_id force_user)
+ WIN_OWNER_AFTER_CHOWN="$SERVER/smbget_user"
+ UNIX_OWNER_AFTER_CHOWN=$(get_unix_id smbget_user)
+ TEST_LABEL="both"
+elif [ "$INH_WIN" = "0" ] && [ "$INH_UNIX" = "1" ]; then
+ #inherit owner=unix only - windows owner is creator,
+ #unix owner inherited, upon change-owner only windows
+ #owner is changed
+ WIN_OWNER_AFTER_CREATE="$SERVER/$USERNAME"
+ UNIX_OWNER_AFTER_CREATE=$(get_unix_id force_user)
+ WIN_OWNER_AFTER_CHOWN="$SERVER/smbget_user"
+ UNIX_OWNER_AFTER_CHOWN=$(get_unix_id force_user)
+ TEST_LABEL="unix"
+else
+ echo "Unknown combination INH_WIN=$INH_WIN INH_UNIX=$INH_UNIX"
+ exit 1
+fi
+
+# SETUP
+testit "$TEST_LABEL - setup root dir" create_dir tmp tmp.$$
+testit "grant SeRestorePrivilege" $NET rpc rights grant $USERNAME SeRestorePrivilege -U $USERNAME%$PASSWORD -I $SERVER || exit 1
+testit "$TEST_LABEL - assign default ACL" $SMBCACLS //$SERVER/tmp tmp.$$ -U $USERNAME%$PASSWORD -S "REVISION:1,OWNER:$SERVER\force_user,GROUP:$SERVER\domusers,ACL:Everyone:ALLOWED/0x3/FULL" 2>/dev/null
+# END SETUP
+
+testit "$TEST_LABEL - create subdir under root" create_dir $SHARE tmp.$$/subdir
+testit "$TEST_LABEL - verify subdir win owner" win_owner_is $SHARE tmp.$$/subdir "$WIN_OWNER_AFTER_CREATE"
+testit "$TEST_LABEL - verify subdir unix owner" unix_owner_id_is $SHARE tmp.$$/subdir $UNIX_OWNER_AFTER_CREATE
+testit "$TEST_LABEL - create file under root" create_file $SHARE tmp.$$/afile
+testit "$TEST_LABEL - verify file win owner" win_owner_is $SHARE tmp.$$/afile "$WIN_OWNER_AFTER_CREATE"
+testit "$TEST_LABEL - verify file unix owner" unix_owner_id_is $SHARE tmp.$$/afile $UNIX_OWNER_AFTER_CREATE
+testit "$TEST_LABEL - change dir owner" set_win_owner $SHARE tmp.$$/subdir "$SERVER\smbget_user"
+testit "$TEST_LABEL - verify subdir win owner after change" win_owner_is $SHARE tmp.$$/subdir "$WIN_OWNER_AFTER_CHOWN"
+testit "$TEST_LABEL - verify subdir unix owner after change" unix_owner_id_is $SHARE tmp.$$/subdir $UNIX_OWNER_AFTER_CHOWN
+testit "$TEST_LABEL - change file owner" set_win_owner $SHARE tmp.$$/afile "$SERVER\smbget_user"
+testit "$TEST_LABEL - verify file win owner after change" win_owner_is $SHARE tmp.$$/afile "$WIN_OWNER_AFTER_CHOWN"
+testit "$TEST_LABEL - verify file unix owner after change" unix_owner_id_is $SHARE tmp.$$/afile $UNIX_OWNER_AFTER_CHOWN
+testit "$TEST_LABEL - cleanup subdir" cleanup_dir $SHARE tmp.$$/subdir
+testit "$TEST_LABEL - cleanup file" cleanup_file $SHARE tmp.$$/afile
+testit "$TEST_LABEL - cleanup root" cleanup_dir $SHARE tmp.$$
+
+testit "revoke SeRestorePrivilege" $NET rpc rights revoke $USERNAME SeRestorePrivilege -U $USERNAME%$PASSWORD -I $SERVER || exit 1
diff --git a/source3/script/tests/test_large_acl.sh b/source3/script/tests/test_large_acl.sh
new file mode 100755
index 0000000..4e98c2e
--- /dev/null
+++ b/source3/script/tests/test_large_acl.sh
@@ -0,0 +1,61 @@
+#!/usr/bin/env bash
+#
+# Blackbox test for fetching a large ACL
+#
+
+if [ $# -lt 5 ]; then
+ cat <<EOF
+Usage: $0 SERVER USERNAME PASSWORD SMBCLIENT SMBCACLS PARAMS
+EOF
+ exit 1
+fi
+
+SERVER=${1}
+USERNAME=${2}
+PASSWORD=${3}
+SMBCLIENT=${4}
+SMBCACLS=${5}
+shift 5
+ADDARGS="$*"
+SMBCLIENT="$VALGRIND ${SMBCLIENT} ${ADDARGS}"
+SMBCACLS="$VALGRIND ${SMBCACLS} ${ADDARGS}"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+cd $SELFTEST_TMPDIR || exit 1
+
+# build a file to work with
+build_files()
+{
+ touch large_acl
+ $SMBCLIENT //$SERVER/acl_xattr_ign_sysacl_windows -U $USERNAME%$PASSWORD -c 'put large_acl' >/dev/null 2>&1
+ rm -rf large_acl >/dev/null
+}
+
+cleanup()
+{
+ $SMBCLIENT //$SERVER/acl_xattr_ign_sysacl_windows -U $USERNAME%$PASSWORD -c 'rm large_acl' >/dev/null 2>&1
+}
+
+build_files
+
+test_large_acl()
+{
+ #An ACL with 200 entries, ~7K
+ new_acl=$(seq 1001 1200 | sed -r -e '1 i\D:(A;;FA;;;WD)' -e 's/(.*)/(A;;FA;;;S-1-5-21-11111111-22222222-33333333-\1)/' | tr -d '\n')
+ $SMBCACLS //$SERVER/acl_xattr_ign_sysacl_windows -U $USERNAME%$PASSWORD --sddl -S $new_acl large_acl
+ actual_acl=$($SMBCACLS //$SERVER/acl_xattr_ign_sysacl_windows -U $USERNAME%$PASSWORD --sddl --numeric large_acl 2>/dev/null | sed -rn 's/.*(D:.*)/\1/p' | tr -d '\n')
+ if [ ! "$new_acl" = "$actual_acl" ]; then
+ echo -e "expected:\n$new_acl\nactual:\n$actual_acl\n"
+ return 1
+ fi
+}
+
+failed=0
+
+testit "able to retrieve a large ACL if VFS supports it" test_large_acl || failed=$(expr $failed + 1)
+
+cleanup
+
+exit $failed
diff --git a/source3/script/tests/test_libwbclient_threads.sh b/source3/script/tests/test_libwbclient_threads.sh
new file mode 100755
index 0000000..4f7ac12
--- /dev/null
+++ b/source3/script/tests/test_libwbclient_threads.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+if [ $# -lt 2 ]; then
+ cat <<EOF
+Usage: test_libwbclient_threads.sh DOMAIN USERNAME
+EOF
+ exit 1
+fi
+
+DOMAIN="$1"
+USERNAME="$2"
+shift 2
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+testit "libwbclient-threads" "$BINDIR/stress-nss-libwbclient" "$DOMAIN/$USERNAME"
diff --git a/source3/script/tests/test_list_nt4_trust.sh b/source3/script/tests/test_list_nt4_trust.sh
new file mode 100755
index 0000000..03ee7fc
--- /dev/null
+++ b/source3/script/tests/test_list_nt4_trust.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+. $incdir/common_test_fns.inc
+
+failed=0
+
+wbinfo="$BINDIR/wbinfo"
+smbclient="$BINDIR/smbclient"
+
+test_trust_wbinfo_m() {
+ i=0
+ # Give the server some time to list trusted domains
+ while [ $i -lt 10 ] ; do
+ $wbinfo -m --verbose | grep "SAMBA-TEST" && return 0
+ sleep 2
+ i=$((i + 1))
+ done
+ return 1
+}
+
+testit "nt4trust_wbinfo_m" test_trust_wbinfo_m || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_local_s3.sh b/source3/script/tests/test_local_s3.sh
new file mode 100755
index 0000000..9de542a
--- /dev/null
+++ b/source3/script/tests/test_local_s3.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+# this runs the file serving tests that are expected to pass with samba3
+
+if [ $# != 0 ]; then
+ cat <<EOF
+Usage: test_local_s3.sh
+EOF
+ exit 1
+fi
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+cd $SELFTEST_TMPDIR || exit 1
+
+if test -x $BINDIR/talloctort; then
+ testit "talloctort" $VALGRIND $BINDIR/talloctort ||
+ failed=$(expr $failed + 1)
+else
+ echo "Skipping talloctort"
+fi
+
+testit "replace_testsuite" $VALGRIND $BINDIR/replace_testsuite ||
+ failed=$(expr $failed + 1)
+
+if test -x $BINDIR/tdbtorture; then
+ testit "tdbtorture" $VALGRIND $BINDIR/tdbtorture ||
+ failed=$(expr $failed + 1)
+else
+ echo "Skipping tdbtorture"
+fi
+
+testit "smbconftort" $VALGRIND $BINDIR/smbconftort $CONFIGURATION ||
+ failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_net_cache_samlogon.sh b/source3/script/tests/test_net_cache_samlogon.sh
new file mode 100755
index 0000000..671806a
--- /dev/null
+++ b/source3/script/tests/test_net_cache_samlogon.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+#
+# Test 'net cache samlogon' command.
+#
+
+if [ $# -lt 4 ]; then
+ cat <<EOF
+Usage: $0 SERVER SHARE USER PASS
+EOF
+ exit 1
+fi
+
+SERVER=$1
+SHARE=$2
+USER=$3
+PASS=$4
+smbclient=$BINDIR/smbclient
+
+failed=0
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+. $incdir/common_test_fns.inc
+
+# Ensure the samlogon cache is primed
+test_smbclient "Prime samlogon cache" 'exit' //$SERVER/$SHARE -U$USER%$PASS || failed=$(expr $failed + 1)
+
+# Ensure list works and remember the sid and name of the first entry
+testit "net cache samlogon list" $BINDIR/net cache samlogon list || failed=$(expr $failed + 1)
+usersid=$($BINDIR/net cache samlogon list | awk '/^S-/ { print $1 ; exit }')
+username=$($BINDIR/net cache samlogon list | awk '/^S-/ { print $2 ; exit }')
+
+# Test the show command with the sid from the previous list command
+testit "net cache samlogon show $usersid" $BINDIR/net cache samlogon show $usersid || failed=$(expr $failed + 1)
+tmp=$($BINDIR/net cache samlogon show $usersid | awk '/^Name:/ {print $2}')
+testit "net cache samlogon show SID name matches name from list command" test x"$tmp" = x"$username" || failed=$(expr $failed + 1)
+
+testit "net cache samlogon ndrdump $usersid" $BINDIR/net cache samlogon ndrdump $usersid || failed=$(expr $failed + 1)
+tmp=$($BINDIR/net cache samlogon ndrdump $usersid | head -n 1 | grep "netr_SamInfo3: struct netr_SamInfo3")
+retval=$?
+testit "net cache samlogon ndrdump returns netr_SamInfo3 structure" test $retval -eq 0 || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_net_conf.sh b/source3/script/tests/test_net_conf.sh
new file mode 100755
index 0000000..7a70a9b
--- /dev/null
+++ b/source3/script/tests/test_net_conf.sh
@@ -0,0 +1,1042 @@
+#!/bin/sh
+#
+# Blackbox test for net [rpc] conf.
+#
+# Copyright (C) 2011 Vicentiu Ciorbaru <cvicentiu@gmail.com>
+
+if [ $# -lt 3 ]; then
+ cat <<EOF
+Usage: test_net_conf.sh SCRIPTDIR SERVERCONFFILE NET CONFIGURATION [rpc]
+EOF
+ exit 1
+fi
+
+SCRIPTDIR="$1"
+SERVERCONFFILE="$2"
+NET="$3"
+CONFIGURATION="$4"
+RPC="$5"
+
+LOGDIR_PREFIX="conf_test"
+
+# remove old logs:
+for OLDDIR in $(find ${PREFIX} -type d -name "${LOGDIR_PREFIX}_*"); do
+ echo "removing old directory ${OLDDIR}"
+ rm -rf ${OLDDIR}
+done
+
+NET="$VALGRIND ${NET:-$BINDIR/net} $CONFIGURATION"
+DIR=$(mktemp -d ${PREFIX}/${LOGDIR_PREFIX}_XXXXXX)
+LOG=$DIR/log
+
+if test "x${RPC}" = "xrpc"; then
+ NETCMD="${NET} -U${USERNAME}%${PASSWORD} -I ${SERVER_IP} rpc"
+else
+ NETCMD="${NET}"
+fi
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+log_print()
+{
+ RC=$?
+ echo "CMD: $*" >>$LOG
+ echo "RC: $RC" >>$LOG
+ return $RC
+ # echo -n .
+}
+
+test_conf_addshare()
+{
+ echo '\nTesting conf addshare' >>$LOG
+ echo ------------------------- >>$LOG
+ echo '\nDropping existing configuration' >>$LOG
+
+ $NETCMD conf drop
+ log_print $NETCMD conf drop
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ #create a lot of shares
+ for i in $(seq 1 100); do
+ if [ $(($i % 2)) -eq 0 ]; then
+ $NETCMD conf addshare share$i /tmp "writeable=y" "guest_ok=n" \
+ "test comment" >>$DIR/addshare_exp \
+ 2>>$DIR/addshare_exp
+ log_print $NETCMD conf addshare share$i /tmp "writeable=y" "guest_ok=n" \
+ "test comment"
+ else
+ $NETCMD conf addshare share$i /tmp "writeable=n" "guest_ok=y" \
+ "test comment" >>$DIR/addshare_exp \
+ 2>>$DIR/addshare_exp
+ log_print $NETCMD conf addshare share$i /tmp "writeable=n" "guest_ok=y" \
+ "test comment"
+ fi
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+ done
+
+ $NETCMD conf listshares >$DIR/listshares_out
+ log_print $NETCMD conf listshares
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ for i in $(seq 1 100); do
+ grep "share$i" $DIR/listshares_out >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: share not found" | tee -a $LOG
+ return 1
+ fi
+ done
+
+ #check the integrity of the shares
+ #if it fails, it can also point to an error in showshare
+ for i in $(seq 1 100); do
+ $NETCMD conf showshare share$i >$DIR/showshare_out
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ grep "path" $DIR/showshare_out >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: share not found" | tee -a $LOG
+ return 1
+ fi
+
+ if [ $(($i % 2)) -eq 0 ]; then
+ grep "read only *= *no" $DIR/showshare_out >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: share not set correctly" | tee -a $LOG
+ return 1
+ fi
+ else
+ grep "read only *= *yes" $DIR/showshare_out >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: share not set correctly" | tee -a $LOG
+ return 1
+ fi
+ fi
+
+ if [ $(($i % 2)) -eq 0 ]; then
+ grep "guest ok *= *no" $DIR/showshare_out >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: share not set correctly" | tee -a $LOG
+ return 1
+ fi
+ else
+ grep "guest ok *= *yes" $DIR/showshare_out >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: share not set correctly" | tee -a $LOG
+ return 1
+ fi
+ fi
+
+ grep "comment *= *test comment" $DIR/showshare_out >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: share not set correctly" | tee -a $LOG
+ return 1
+ fi
+ done
+
+ echo '\nTaking a conf snapshot for later use' >>$LOG
+ $NETCMD conf list >$DIR/conf_import_in
+ log_print $NETCMD conf list
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+}
+
+test_conf_addshare_existing()
+{
+ #try adding an already existing share
+ echo '\nAdding an already existing share' >>$LOG
+ $NETCMD conf addshare share1 /tmp "writeable=n" "guest_ok=y" \
+ "test comment" >>$DIR/addshare_exp \
+ 2>>$DIR/addshare_exp
+ log_print $NETCMD conf addshare share1 /tmp "writeable=n" "guest_ok=y" \
+ "test comment"
+ test "x$?" = "x255" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ test -z $(cat $DIR/addshare_exp) && {
+ echo "ERROR: addshare output does not match" >>$LOG
+ return 1
+ }
+
+ return 0
+}
+
+test_conf_addshare_usage()
+{
+ #check to see if command prints usage
+ echo '\nChecking usage' >>$LOG
+ $NETCMD conf addshare >$DIR/addshare_usage_exp
+ log_print $NETCMD conf addshare
+ test "x$?" = "x255" || {
+ echo 'ERROR: RC does not match, expected: 255' | tee -a $LOG
+ return 1
+ }
+
+ grep "$RPC *conf addshare" $DIR/addshare_usage_exp >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: no/wrong usage message printed" | tee -a $LOG
+ return 1
+ fi
+}
+
+test_conf_delshare()
+{
+ echo '\nTesting conf delshare' >>$LOG
+ echo ------------------------- >>$LOG
+ echo -n '\n' >>$LOG
+
+ $NETCMD conf delshare share1
+ log_print $NETCMD conf delshare share1
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf listshares >$DIR/listshares_out
+ log_print $NETCMD conf listshares
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ grep "share1$" $DIR/listshares_out >/dev/null 2>>$LOG
+ if [ "$?" = "0" ]; then
+ echo "ERROR: delshare did not delete 'share1'" | tee -a $LOG
+ return 1
+ fi
+}
+
+test_conf_delshare_empty()
+{
+ echo '\nAttempting to delete non_existing share'
+ $NETCMD conf delshare share1
+ log_print $NETCMD conf delshare share1
+ test "x$?" = "x255" || {
+ echo 'ERROR: RC does not match, expected: 255' | tee -a $LOG
+ return 1
+ }
+
+}
+
+test_conf_delshare_usage()
+{
+ echo '\nChecking usage' >>$LOG
+ $NETCMD conf delshare >$DIR/delshare_usage_exp
+ log_print $NETCMD conf delshare
+ test "x$?" = "x255" || {
+ echo 'ERROR: RC does not match, expected: 255' | tee -a $LOG
+ return 1
+ }
+
+ grep "$RPC *conf delshare" $DIR/delshare_usage_exp >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: no/wrong usage message printed" | tee -a $LOG
+ return 1
+ fi
+}
+
+test_conf_showshare_case()
+{
+ echo '\nChecking case in net conf shareshare' >>$LOG
+
+ echo '\nDropping existing configuration' >>$LOG
+ $NETCMD conf drop
+ log_print $NETCMD conf drop
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ for share in UPPERCASE lowercase; do
+
+ log_print $NETCMD conf addshare $share /tmp
+ $NETCMD conf addshare $share /tmp \
+ >>$DIR/case_addshare_exp \
+ 2>>$DIR/case_addshare_exp
+
+ # Lookup share in different case, check that output has
+ # share name in correct case.
+ switch_case=$(echo $share | tr 'A-Za-z' 'a-zA-Z')
+ log_print $NETCMD conf showshare $switch_case
+ $NETCMD conf showshare $switch_case >$DIR/showshare_out
+ test "x$?" = "x0" || {
+ echo 'ERROR: net conf showshare failed.' | tee -a $LOG
+ return 1
+ }
+
+ grep "\[$share\]" $DIR/showshare_out >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: share not found" | tee -a $LOG
+ return 1
+ fi
+ done
+
+}
+
+test_conf_drop()
+{
+
+ echo '\nTesting conf drop' >>$LOG
+ echo ------------------------- >>$LOG
+ echo '\nDropping existing configuration' >>$LOG
+
+ $NETCMD conf drop
+ log_print $NETCMD conf drop
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ #check to see if listing the configuration yields a blank file
+ $NETCMD conf list 1>>$DIR/list_out
+ log_print $NETCMD conf list
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ test -z "$(cat $DIR/list_out)" || {
+ echo "ERROR: Expected list output did not match" | tee -a $LOG
+ return 1
+ }
+}
+
+test_conf_drop_empty()
+{
+ #Drop an empty config, see if conf drop fails
+ echo '\nAttempting to drop an empty configuration' >>$LOG
+
+ $NETCMD conf drop
+ log_print $NETCMD conf drop
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ #check to see if listing the configuration yields a blank file
+ $NETCMD conf list 1>>$DIR/list_out
+ log_print $NETCMD conf list
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ test -z "$(cat $DIR/list_out)" || {
+ echo ERROR:Expected list output did not match >>$LOG
+ return 1
+ }
+}
+
+test_conf_drop_usage()
+{
+ #check to see if command prints usage
+ echo '\nChecking usage' >>$LOG
+ $NETCMD conf drop extra_arg >$DIR/drop_usage_exp
+ log_print $NETCMD conf drop extra_arg
+ test "x$?" = "x255" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ grep "$RPC *conf drop" $DIR/drop_usage_exp >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: no/wrong usage message printed" | tee -a $LOG
+ return 1
+ fi
+}
+
+test_conf_setparm()
+{
+ echo '\nTesting conf setparm' >>$LOG
+ echo ------------------------- >>$LOG
+
+ echo '\nDropping existing configuration' >>$LOG
+ $NETCMD conf drop
+ log_print $NETCMD conf drop
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf setparm share1 "read only" yes
+ log_print $NETCMD conf setparm share1 "read only" yes
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf setparm share1 "path" /tmp/test_path
+ log_print $NETCMD conf setparm share1 "path" /tmp/test_path
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf showshare share1 >$DIR/setparm_showshare_out
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ grep "read only *= *yes" $DIR/setparm_showshare_out >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: setparm did not set correctly" | tee -a $LOG
+ return 1
+ fi
+
+ grep "path *= */tmp/test_path" $DIR/setparm_showshare_out >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: setparm did not set correctly" | tee -a $LOG
+ return 1
+ fi
+}
+
+test_conf_setparm_existing()
+{
+
+ echo '\nSetting already existing param with the same value'
+ $NETCMD conf setparm share1 "read only" yes
+ log_print $NETCMD conf setparm share1 "read only" yes
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf setparm share1 "read only" yes
+ log_print $NETCMD conf setparm share1 "read only" yes
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf showshare share1 >$DIR/setparm_existing_showshare_out
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ grep "read only *= *yes" $DIR/setparm_existing_showshare_out >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: setparm did not set correctly" | tee -a $LOG
+ return 1
+ fi
+
+ $NETCMD conf setparm share1 "read only" no
+ log_print $NETCMD conf setparm share1 "read only" no
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf showshare share1 >$DIR/setparm_existing_showshare_out
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ grep "read only *= *no" $DIR/setparm_existing_showshare_out >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: setparm did not set correctly" | tee -a $LOG
+ return 1
+ fi
+}
+
+test_conf_setparm_forbidden()
+{
+ FORBIDDEN_PARAMS="state directory
+lock directory
+lock dir
+config backend
+include"
+
+ echo '\nTrying to set forbidden parameters' >>$LOG
+
+ echo '\nDropping existing configuration' >>$LOG
+ $NETCMD conf drop
+ log_print $NETCMD conf drop
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ OLD_IFS="$IFS"
+ IFS='
+'
+ for PARAM in $FORBIDDEN_PARAMS; do
+ IFS="$OLD_IFS"
+ echo "Trying to set parameter '$PARAM'" | tee -a $LOG
+ $NETCMD conf setparm global "$PARAM" "value" >$DIR/setparm_forbidden_out 2>&1
+ log_print $NETCMD conf setparm global \""$PARAM"\" "value"
+ test "x$?" = "x0" && {
+ echo "ERROR: setting forbidden parameter '$PARAM' succeeded" | tee -a $LOG
+ return 1
+ }
+
+ echo "output of net command: " | tee -a $LOG
+ cat $DIR/setparm_forbidden_out | tee -a $LOG
+
+ SEARCH="Parameter '$PARAM' not allowed in registry."
+ grep "$SEARCH" $DIR/setparm_forbidden_out >/dev/null 2>>$LOG
+ test "x$?" = "x0" || {
+ echo "ERROR: expected '$SEARCH'" | tee -a $LOG
+ return 1
+ }
+ done
+
+ IFS="$OLD_IFS"
+ return 0
+}
+
+test_conf_setparm_usage()
+{
+ echo '\nChecking usage' >>$LOG
+ $NETCMD conf setparm >$DIR/setparm_usage_exp
+ log_print $NETCMD conf setparm
+ test "x$?" = "x255" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ grep "$RPC *conf setparm" $DIR/setparm_usage_exp >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: setparm no/wrong usage message printed" | tee -a $LOG
+ return 1
+ fi
+}
+
+test_conf_delparm_delete_existing()
+{
+ echo '\nTesting conf delparm' >>$LOG
+ echo ------------------------- >>$LOG
+ echo -n '\n' >>$LOG
+
+ $NETCMD conf drop
+ log_print $NETCMD conf drop
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf addshare share1 /tmp "writeable=y" "guest_ok=n" \
+ "test comment"
+ log_print $NETCMD conf addshare share$i /tmp "writeable=y" "guest_ok=n" \
+ "test comment"
+
+ $NETCMD conf delparm share1 "path"
+ log_print $NETCMD conf delparm share1 "path"
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf showshare share1 >$DIR/delparm_showshare_out
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ #test to see what delparm did delete and how
+ grep "read only *= *no" $DIR/delparm_showshare_out >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: delparm did not delete correctly" | tee -a $LOG
+ return 1
+ fi
+
+ grep "path *= */tmp" $DIR/delparm_showshare_out >/dev/null 2>>$LOG
+ if [ "$?" = "0" ]; then
+ echo "ERROR: delparm did not delete correctly" | tee -a $LOG
+ return 1
+ fi
+}
+
+test_conf_delparm_delete_non_existing()
+{
+ echo '\nDelete non existing share' >>$LOG
+
+ $NETCMD conf drop
+ log_print $NETCMD conf drop
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf delparm share1 "path"
+ log_print $NETCMD conf delparm share1 "path"
+ test "x$?" = "x255" || {
+ echo 'ERROR: RC does not match, expected: 255' | tee -a $LOG
+ return 1
+ }
+}
+
+test_conf_delparm_usage()
+{
+
+ echo '\nChecking usage' >>$LOG
+ $NETCMD conf delparm >$DIR/delparm_usage_exp
+ log_print $NETCMD conf delparm
+ test "x$?" = "x255" || {
+ echo 'ERROR: RC does not match, expected: 255' | tee -a $LOG
+ return 1
+ }
+
+ grep "$RPC *conf delparm" $DIR/delparm_usage_exp >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: delparm no/wrong usage message printed" | tee -a $LOG
+ return 1
+ fi
+
+}
+
+test_conf_getparm()
+{
+
+ echo '\nTesting conf getparm' >>$LOG
+ echo ------------------------- >>$LOG
+ echo -n '\n' >>$LOG
+
+ $NETCMD conf drop
+ log_print $NETCMD conf drop
+ test "x$?" = "x0" || {
+ return 1
+ }
+
+ $NETCMD conf addshare share1 /tmp/path_test "writeable=n" "guest_ok=n" \
+ "test comment"
+ log_print $NETCMD conf addshare share$i /tmp/path_test "writeable=n" "guest_ok=n" \
+ "test comment"
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf getparm share1 "read only" >$DIR/getparm_out
+ log_print $NETCMD conf getparm share1 "read only"
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf getparm share1 "read only" >$DIR/getparm_out
+ log_print $NETCMD conf getparm share1 "read only"
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ echo yes >$DIR/getparm_exp
+ diff -q $DIR/getparm_out $DIR/getparm_exp >>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: getparm did not print correctly" | tee -a $LOG
+ return 1
+ fi
+
+ $NETCMD conf getparm share1 "path" >$DIR/getparm_out
+ log_print $NETCMD conf getparm share1 "path"
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ echo /tmp/path_test >$DIR/getparm_exp
+ diff -q $DIR/getparm_out $DIR/getparm_exp >>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: getparm did not print correctly" | tee -a $LOG
+ return 1
+ fi
+}
+
+test_conf_getparm_usage()
+{
+ echo '\nChecking usage' >>$LOG
+ $NETCMD conf getparm >$DIR/getparm_usage_exp
+ log_print $NETCMD conf getparm
+ test "x$?" = "x255" || {
+ echo 'ERROR: RC does not match, expected: 255' | tee -a $LOG
+ return 1
+ }
+
+ grep "$RPC *conf getparm" $DIR/getparm_usage_exp >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: getparm no/wrong usage message printed" | tee -a $LOG
+ return 1
+ fi
+
+}
+
+test_conf_getparm_non_existing()
+{
+ echo '\nTesting getparm non existing' >>$LOG
+ $NETCMD conf getparm fictional_share fictional_param
+ log_print $NETCMD conf getparm fictional_share fictional_param
+ test "x$?" = "x255" || {
+ echo 'ERROR: RC does not match, expected: 255' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf getparm share1 fictional_param
+ log_print $NETCMD conf getparm share1 fictional_param
+ test "x$?" = "x255" || {
+ echo 'ERROR: RC does not match, expected: 255' | tee -a $LOG
+ return 1
+ }
+}
+
+test_conf_setincludes()
+{
+ echo '\nTesting conf setincludes' >>$LOG
+ echo ------------------------- >>$LOG
+ echo '\nDropping existing configuration' >>$LOG
+
+ $NETCMD conf drop
+ log_print $NETCMD conf drop
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf addshare tmp_share /tmp
+ log_print $NETCMD conf addshare tmp_share /tmp
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf setincludes tmp_share /tmp/include1 /tmp/include2 /tmp/include3
+ log_print $NETCMD conf setincludes tmp_share /tmp/include1 /tmp/include2 /tmp/include3
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf list >$DIR/setincludes_list_out
+ log_print $NETCMD conf list
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ grep "include *= */tmp/include1$" $DIR/setincludes_list_out >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: setincludes did not set correctly" | tee -a $LOG
+ return 1
+ fi
+
+ grep "include *= */tmp/include2$" $DIR/setincludes_list_out >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: setincludes did not set correctly" | tee -a $LOG
+ return 1
+ fi
+
+ grep "include *= */tmp/include3$" $DIR/setincludes_list_out >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: setincludes did not set correctly" | tee -a $LOG
+ return 1
+ fi
+
+}
+
+test_conf_setincludes_usage()
+{
+ echo '\nChecking usage' >>$LOG
+ $NETCMD conf setincludes >$DIR/setincludes_usage_exp
+ log_print $NETCMD conf setincludes
+ test "x$?" = "x255" || {
+ echo 'ERROR: RC does not match, expected: 255' | tee -a $LOG
+ return 1
+ }
+
+ grep "$RPC *conf setincludes" $DIR/setincludes_usage_exp >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: no/wrong usage message printed" | tee -a $LOG
+ return 1
+ fi
+}
+
+test_conf_getincludes()
+{
+ $NETCMD conf getincludes tmp_share >$DIR/getincludes_out
+ log_print $NETCMD conf getincludes tmp_share
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ grep "include *= */tmp/include1$" $DIR/getincludes_out >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: getincludes did not print correctly" | tee -a $LOG
+ return 1
+ fi
+
+ grep "include *= */tmp/include2$" $DIR/getincludes_out >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: getincludes did not print correctly" | tee -a $LOG
+ return 1
+ fi
+ grep "include *= */tmp/include3$" $DIR/getincludes_out >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: getincludes did not print correctly" | tee -a $LOG
+ return 1
+ fi
+}
+
+test_conf_getincludes_usage()
+{
+ $NETCMD conf getincludes >$DIR/getincludes_usage_exp
+ log_print $NETCMD conf getincludes
+
+ grep "$RPC *conf getincludes" $DIR/getincludes_usage_exp >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: no/wrong usage message printed" | tee -a $LOG
+ return 1
+ fi
+}
+
+test_conf_delincludes()
+{
+ echo '\nTesting conf delincludes' >>$LOG
+ echo ------------------------- >>$LOG
+
+ $NETCMD conf delincludes tmp_share
+ log_print $NETCMD conf delincludes tmp_share
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf list >$DIR/delincludes_list_out
+ log_print $NETCMD conf list
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ grep "include" $DIR/delincludes_list_out >/dev/null 2>>$LOG
+ if [ "$?" = "0" ]; then
+ echo "ERROR: delincludes did not delete correctly" | tee -a $LOG
+ return 1
+ fi
+}
+
+test_conf_delincludes_empty()
+{
+ $NETCMD conf delincludes tmp_share
+ log_print $NETCMD conf delincludes tmp_share
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf delincludes fictional_share
+ log_print $NETCMD conf delincludes fictional_share
+ test "x$?" = "x255" || {
+ echo 'ERROR: RC does not match, expected: 255' | tee -a $LOG
+ return 1
+ }
+ return 0
+}
+
+test_conf_delincludes_usage()
+{
+ echo '\nChecking usage' >>$LOG
+ $NETCMD conf delincludes >$DIR/delincludes_usage_exp
+ log_print $NETCMD conf delincludes
+ test "x$?" = "x255" || {
+ echo 'ERROR: RC does not match, expected: 255' | tee -a $LOG
+ return 1
+ }
+
+ grep "$RPC *conf delincludes" $DIR/delincludes_usage_exp >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: no/wrong usage message printed" | tee -a $LOG
+ return 1
+ fi
+}
+
+test_conf_import()
+{
+ echo '\nTesting conf import' >>$LOG
+ echo ------------------------- >>$LOG
+ echo '\nDropping existing configuration' >>$LOG
+
+ $NETCMD conf drop
+ log_print $NETCMD conf drop
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf import $DIR/conf_import_in
+ log_print $NETCMD conf drop
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ $NETCMD conf list >$DIR/conf_import_out
+ log_print $NETCMD conf list
+ test "x$?" = "x0" || {
+ echo 'ERROR: RC does not match, expected: 0' | tee -a $LOG
+ return 1
+ }
+
+ diff -q $DIR/conf_import_in $DIR/conf_import_out >>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: import failed" | tee -a $LOG
+ return 1
+ fi
+}
+
+test_conf_import_usage()
+{
+ echo '\nChecking usage' >>$LOG
+ $NETCMD conf import >$DIR/import_usage_exp
+ log_print $NETCMD conf import
+ test "x$?" = "x255" || {
+ echo 'ERROR: RC does not match, expected: 255' | tee -a $LOG
+ return 1
+ }
+
+ grep "$RPC *conf import" $DIR/import_usage_exp >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: conf import no/wrong usage message printed" | tee -a $LOG
+ return 1
+ fi
+}
+
+CONF_FILES=$SERVERCONFFILE
+
+testit "conf_drop" \
+ test_conf_drop ||
+ failed=$(expr $failed + 1)
+
+testit "conf_drop_empty" \
+ test_conf_drop_empty ||
+ failed=$(expr $failed + 1)
+
+testit "conf_drop_usage" \
+ test_conf_drop_usage ||
+ failed=$(expr $failed + 1)
+
+testit "conf_addshare" \
+ test_conf_addshare ||
+ failed=$(expr $failed + 1)
+
+testit "conf_addshare_existing" \
+ test_conf_addshare_existing ||
+ failed=$(expr $failed + 1)
+
+testit "conf_addshare_usage" \
+ test_conf_addshare_usage ||
+ failed=$(expr $failed + 1)
+
+testit "conf_delshare" \
+ test_conf_delshare ||
+ failed=$(expr $failed + 1)
+
+testit "conf_delshare_empty" \
+ test_conf_delshare_empty ||
+ failed=$(expr $failed + 1)
+
+testit "conf_delshare_usage" \
+ test_conf_delshare_usage ||
+ failed=$(expr $failed + 1)
+
+testit "test_conf_showshare_case" \
+ test_conf_showshare_case ||
+ failed=$(expr $failed + 1)
+
+testit "conf_setparm" \
+ test_conf_setparm ||
+ failed=$(expr $failed + 1)
+
+testit "conf_setparm_existing" \
+ test_conf_setparm_existing ||
+ failed=$(expr $failed + 1)
+
+testit "conf_setparm_forbidden" \
+ test_conf_setparm_forbidden ||
+ failed=$(expr $failed + 1)
+
+testit "conf_setparm_usage" \
+ test_conf_setparm_usage ||
+ failed=$(expr $failed + 1)
+
+testit "conf_delparm_delete_existing" \
+ test_conf_delparm_delete_existing ||
+ failed=$(expr $failed + 1)
+
+testit "conf_delparm_delete_non_existing" \
+ test_conf_delparm_delete_non_existing ||
+ failed=$(expr $failed + 1)
+
+testit "conf_delparm_delete_usage" \
+ test_conf_delparm_usage ||
+ failed=$(expr $failed + 1)
+
+testit "conf_getparm" \
+ test_conf_getparm ||
+ failed=$(expr $failed + 1)
+
+testit "conf_getparm_usage" \
+ test_conf_getparm_usage ||
+ failed=$(expr $failed + 1)
+
+testit "conf_setincludes" \
+ test_conf_setincludes ||
+ failed=$(expr $failed + 1)
+
+testit "conf_setincludes_usage" \
+ test_conf_setincludes_usage ||
+ failed=$(expr $failed + 1)
+
+testit "conf_getincludes" \
+ test_conf_getincludes ||
+ failed=$(expr $failed + 1)
+
+testit "conf_getincludes_usage" \
+ test_conf_getincludes_usage ||
+ failed=$(expr $failed + 1)
+
+testit "conf_delincludes" \
+ test_conf_delincludes ||
+ failed=$(expr $failed + 1)
+
+testit "conf_delincludes_empty" \
+ test_conf_delincludes_usage ||
+ failed=$(expr $failed + 1)
+
+testit "conf_delincludes_usage" \
+ test_conf_delincludes_empty ||
+ failed=$(expr $failed + 1)
+
+testit "conf_import" \
+ test_conf_import ||
+ failed=$(expr $failed + 1)
+
+testit "conf_import_usage" \
+ test_conf_import_usage ||
+ failed=$(expr $failed + 1)
+
+if [ $failed -eq 0 ]; then
+ rm -r $DIR
+fi
+
+testok $0 $failed
diff --git a/source3/script/tests/test_net_cred_change.sh b/source3/script/tests/test_net_cred_change.sh
new file mode 100755
index 0000000..7b01673
--- /dev/null
+++ b/source3/script/tests/test_net_cred_change.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+if [ $# -lt 1 ]; then
+ cat <<EOF
+Usage: test_net_cred_change.sh CONFIGURATION
+EOF
+ exit 1
+fi
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+testit "1: change machine secret" $VALGRIND $BINDIR/wbinfo --change-secret || failed=$(expr $failed + 1)
+testit "1: validate secret" $VALGRIND $BINDIR/net rpc testjoin "$@" || failed=$(expr $failed + 1)
+testit "2: change machine secret" $VALGRIND $BINDIR/wbinfo --change-secret || failed=$(expr $failed + 1)
+testit "2: validate secret" $VALGRIND $BINDIR/net rpc testjoin "$@" || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_net_cred_change_at.sh b/source3/script/tests/test_net_cred_change_at.sh
new file mode 100755
index 0000000..47434bc
--- /dev/null
+++ b/source3/script/tests/test_net_cred_change_at.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+
+if [ $# -lt 2 ]; then
+ cat <<EOF
+Usage: test_net_cred_change_at.sh CONFIGURATION
+EOF
+ exit 1
+fi
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+# shellcheck source=/dev/null
+. "$incdir/subunit.sh"
+
+test_change_machine_secret_at() {
+ local DC_SERVER
+ local REPL_TARGET
+
+ out=$("$BINDIR/wbinfo" --dc-info SAMBADOMAIN) || return 1
+ echo "$out"
+ echo "$out" | grep localdc && DC_SERVER=localvampiredc && REPL_TARGET=localdc
+ echo "$out" | grep localvampiredc && DC_SERVER=localdc && REPL_TARGET=localvampiredc
+ if [ -z $DC_SERVER ] ; then return 1 ; fi
+
+ $VALGRIND "$BINDIR/wbinfo" --change-secret-at=$DC_SERVER || return 1
+
+ # Force replication
+ $VALGRIND "$BINDIR/samba-tool" drs replicate -U Administrator%locDCpass1 $REPL_TARGET $DC_SERVER DC=samba,DC=example,DC=com
+}
+
+testit "change machine secret at" test_change_machine_secret_at || failed=$(("$failed" + 1))
+testit "validate secret" $VALGRIND "$BINDIR/net rpc testjoin" "$@" || failed=$(("$failed" + 1))
+
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_net_dom_join_fail_dc.sh b/source3/script/tests/test_net_dom_join_fail_dc.sh
new file mode 100755
index 0000000..4367492
--- /dev/null
+++ b/source3/script/tests/test_net_dom_join_fail_dc.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+if [ $# -lt 4 ]; then
+ cat <<EOF
+Usage: test_net_dom_join_fail_dc.sh USERNAME PASSWORD DOMAIN PREFIX
+EOF
+ exit 1
+fi
+
+DC_USERNAME="$1"
+DC_PASSWORD="$2"
+DOMAIN="$3"
+PREFIX="$4"
+shift 4
+ADDARGS="$*"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+mkdir -p $PREFIX/private
+testit_expect_failure "net_dom_join_fail_dc" $VALGRIND $BINDIR/net dom join domain=$DOMAIN account=$USERNAME password=$PASSWORD --option=netbiosname=netrpcjointest --option=domainlogons=yes --option=privatedir=$PREFIX/private $ADDARGS || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_net_lookup.sh b/source3/script/tests/test_net_lookup.sh
new file mode 100755
index 0000000..ee18333
--- /dev/null
+++ b/source3/script/tests/test_net_lookup.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+if [ $# != 6 ]; then
+ echo "Usage: $0 SERVER USERNAME PASSWORD NET SAMBA-TOOL DNS-ZONE"
+ exit 1
+fi
+
+SERVER="$1"
+shift 1
+USERNAME="$1"
+shift 1
+PASSWORD="$1"
+shift 1
+NET="$1"
+shift 1
+SAMBATOOL="$1"
+shift 1
+DNSZONE="$1"
+shift 1
+
+SITE="mysite"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+$SAMBATOOL dns add "$SERVER" -U "$USERNAME"%"$PASSWORD" \
+ _msdcs."$DNSZONE" _ldap._tcp."$SITE"._sites.dc \
+ SRV "mydc.$DNSZONE 389 100 100"
+$SAMBATOOL dns add "$SERVER" -U "$USERNAME"%"$PASSWORD" \
+ "$DNSZONE" mydc \
+ A "1.2.3.4"
+
+# global lookup
+testit_grep global 10.53.57.30:389 $NET lookup ldap "$DNSZONE" ||
+ failed=$(expr $failed + 1)
+
+# correct site-aware lookup
+testit_grep site-aware 1.2.3.4:389 $NET lookup ldap "$DNSZONE" "$SITE" ||
+ failed=$(expr $failed + 1)
+
+# lookup with nonexisting site -- global fallback
+testit_grep global 10.53.57.30:389 $NET lookup ldap "$DNSZONE" nosite ||
+ failed=$(expr $failed + 1)
+
+$SAMBATOOL dns delete "$SERVER" -U "$USERNAME"%"$PASSWORD" \
+ "$DNSZONE" mydc \
+ A "1.2.3.4"
+$SAMBATOOL dns delete "$SERVER" -U "$USERNAME"%"$PASSWORD" \
+ _msdcs."$DNSZONE" _ldap._tcp."$SITE"._sites.dc \
+ SRV "mydc.$DNSZONE 389 100 100"
+
+testok $0 $failed
diff --git a/source3/script/tests/test_net_machine_account.sh b/source3/script/tests/test_net_machine_account.sh
new file mode 100755
index 0000000..ad1d099
--- /dev/null
+++ b/source3/script/tests/test_net_machine_account.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+# Reproducer for https://bugzilla.samba.org/show_bug.cgi?id=14908
+
+if [ $# -lt 2 ]; then
+ echo "Usage: $0 NET CONFFILE SERVER_IP"
+ exit 1
+fi
+
+NET="$1"
+shift
+CONFFILE="$1"
+shift
+SERVER_IP="$1"
+shift
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+net_ads_user() {
+ _out=$(UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 \
+ ${VALGRIND} "${NET}" rpc user \
+ --configfile="${CONFFILE}" -S "${SERVER_IP}" -P)
+ _ret=$?
+
+ echo "${_out}"
+
+ return ${_ret}
+}
+
+testit "net_ads_user" net_ads_user || failed=$((failed + 1))
+
+testok $0 $failed
diff --git a/source3/script/tests/test_net_misc.sh b/source3/script/tests/test_net_misc.sh
new file mode 100755
index 0000000..3c2c01f
--- /dev/null
+++ b/source3/script/tests/test_net_misc.sh
@@ -0,0 +1,80 @@
+#!/bin/sh
+
+# various tests for the "net" command
+
+if [ $# -lt 3 ]; then
+ cat <<EOF
+Usage: test_net_misc.sh SCRIPTDIR SERVERCONFFILE NET CONFIGURATION
+EOF
+ exit 1
+fi
+
+SCRIPTDIR="$1"
+SERVERCONFFILE="$2"
+NET="$3"
+CONFIGURATION="$4"
+
+# optional protocol, default to NT1
+if [ $# -gt 4 ]; then
+ PROTOCOL="$5"
+else
+ PROTOCOL="NT1"
+fi
+
+NET="$VALGRIND ${NET:-$BINDIR/net} $CONFIGURATION"
+NETTIME="${NET} --option=clientmaxprotocol=${PROTOCOL} time"
+NETLOOKUP="${NET} --option=clientmaxprotocol=${PROTOCOL} lookup"
+NETSHARE="${NET} -U${USERNAME}%${PASSWORD} --option=clientmaxprotocol=${PROTOCOL} -S ${SERVER} share"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+test_time()
+{
+ PARAM="$1"
+
+ ${NETTIME} -S ${SERVER} ${PARAM}
+}
+
+test_lookup()
+{
+ PARAM="$1"
+
+ ${NETLOOKUP} ${PARAM}
+}
+
+test_share()
+{
+ PARAM="$1"
+
+ ${NETSHARE} ${PARAM}
+}
+
+testit "get the time" \
+ test_time ||
+ failed=$(expr $failed + 1)
+
+testit "get the system time" \
+ test_time system ||
+ failed=$(expr $failed + 1)
+
+testit "get the time zone" \
+ test_time zone ||
+ failed=$(expr $failed + 1)
+
+testit "lookup the PDC" \
+ test_lookup pdc ||
+ failed=$(expr $failed + 1)
+
+testit "lookup the master browser" \
+ test_lookup master ||
+ failed=$(expr $failed + 1)
+
+# This test attempts to lookup shares
+testit "lookup share list" \
+ test_share list ||
+ failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_net_registry.sh b/source3/script/tests/test_net_registry.sh
new file mode 100755
index 0000000..155533e
--- /dev/null
+++ b/source3/script/tests/test_net_registry.sh
@@ -0,0 +1,411 @@
+#!/bin/sh
+#
+# Blackbox tests for the "net registry" and "net rpc registry" commands.
+#
+# Copyright (C) 2010-2011 Michael Adam <obnox@samba.org>
+# Copyright (C) 2010 Gregor Beck <gbeck@sernet.de>
+#
+# rpc tests are chose by specifying "rpc" as commandline parameter.
+
+if [ $# -lt 3 ]; then
+ cat <<EOF
+Usage: test_net_registry.sh SCRIPTDIR SERVERCONFFILE NET CONFIGURATION RPC
+EOF
+ exit 1
+fi
+
+SCRIPTDIR="$1"
+SERVERCONFFILE="$2"
+NET="$3"
+CONFIGURATION="$4"
+RPC="$5"
+
+NET="$VALGRIND ${NET:-$BINDIR/net} $CONFIGURATION"
+
+if test "x${RPC}" = "xrpc"; then
+ NETREG="${NET} -U${USERNAME}%${PASSWORD} -I ${SERVER_IP} rpc registry"
+else
+ NETREG="${NET} registry"
+fi
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+test_enumerate()
+{
+ KEY="$1"
+
+ ${NETREG} enumerate ${KEY}
+}
+
+test_getsd()
+{
+ KEY="$1"
+
+ ${NETREG} getsd ${KEY}
+}
+
+test_enumerate_nonexisting()
+{
+ KEY="$1"
+ ${NETREG} enumerate ${KEY}
+
+ if test "x$?" = "x0"; then
+ echo "ERROR: enumerate succeeded with key '${KEY}'"
+ false
+ else
+ true
+ fi
+}
+
+test_enumerate_no_key()
+{
+ ${NETREG} enumerate
+ if test "x$?" = "x0"; then
+ echo "ERROR: enumerate succeeded without any key specified"
+ false
+ else
+ true
+ fi
+}
+
+test_create_existing()
+{
+ KEY="HKLM"
+ EXPECTED="createkey opened existing ${KEY}"
+
+ OUTPUT=$(${NETREG} createkey ${KEY})
+ if test "x$?" = "x0"; then
+ if test "$OUTPUT" = "$EXPECTED"; then
+ true
+ else
+ echo "got '$OUTPUT', expected '$EXPECTED'"
+ false
+ fi
+ else
+ printf "%s\n" "$OUTPUT"
+ false
+ fi
+}
+
+test_createkey()
+{
+ KEY="$1"
+ BASEKEY=$(dirname $KEY)
+ SUBKEY=$(basename $KEY)
+
+ OUTPUT=$(${NETREG} createkey ${KEY})
+ if test "x$?" != "x0"; then
+ echo "ERROR: createkey ${KEY} failed"
+ echo "output:"
+ printf "%s\n" "$OUTPUT"
+ false
+ return
+ fi
+
+ # check enumerate of basekey lists new key:
+ OUTPUT=$(${NETREG} enumerate ${BASEKEY})
+ if test "x$?" != "x0"; then
+ echo "ERROR: failed to enumerate key '${BASEKEY}'"
+ echo "output:"
+ printf "%s\n" "$OUTPUT"
+ false
+ return
+ fi
+
+ EXPECTED="Keyname = ${SUBKEY}"
+ printf "%s\n" "$OUTPUT" | grep '^Keyname' | grep ${SUBKEY}
+ if test "x$?" != "x0"; then
+ echo "ERROR: did not find expected '$EXPECTED' in output"
+ echo "output:"
+ printf "%s\n" "$OUTPUT"
+ false
+ fi
+
+ # check enumerate of new key works:
+ ${NETREG} enumerate ${KEY}
+}
+
+test_deletekey()
+{
+ KEY="$1"
+ BASEKEY=$(dirname ${KEY})
+ SUBKEY=$(basename ${KEY})
+
+ OUTPUT=$(test_createkey "${KEY}")
+ if test "x$?" != "x0"; then
+ printf "%s\n" "${OUTPUT}"
+ false
+ return
+ fi
+
+ OUTPUT=$(${NETREG} deletekey ${KEY})
+ if test "x$?" != "x0"; then
+ printf "%s\n" "${OUTPUT}"
+ false
+ return
+ fi
+
+ # check enumerate of basekey does not show key anymore:
+ OUTPUT=$(${NETREG} enumerate ${BASEKEY})
+ if test "x$?" != "x0"; then
+ printf "%s\n" "$OUTPUT"
+ false
+ return
+ fi
+
+ UNEXPECTED="Keyname = ${SUBKEY}"
+ printf "%s\n" "$OUTPUT" | grep '^Keyname' | grep ${SUBKEY}
+ if test "x$?" = "x0"; then
+ echo "ERROR: found '$UNEXPECTED' after delete in output"
+ echo "output:"
+ printf "%s\n" "$OUTPUT"
+ false
+ fi
+
+ # check enumerate of key itself does not work anymore:
+ ${NETREG} enumerate ${KEY}
+ if test "x$?" = "x0"; then
+ echo "ERROR: 'enumerate ${KEY}' works after 'deletekey ${KEY}'"
+ false
+ else
+ true
+ fi
+}
+
+test_deletekey_nonexisting()
+{
+ KEY="$1"
+
+ OUTPUT=$(test_deletekey "${KEY}")
+ if test "x$?" != "x0"; then
+ printf "%s\n" "${OUTPUT}"
+ false
+ return
+ fi
+
+ ${NETREG} deletekey "${KEY}"
+ if test "x$?" = "x0"; then
+ echo "ERROR: delete after delete succeeded for key '${KEY}'"
+ false
+ fi
+}
+
+test_createkey_with_subkey()
+{
+ KEY="$1"
+ KEY2=$(dirname ${KEY})
+ SUBKEYNAME2=$(basename ${KEY})
+ BASENAME=$(dirname ${KEY2})
+ SUBKEYNAME1=$(basename ${KEY2})
+
+ OUTPUT=$(${NETREG} createkey ${KEY})
+ if test "x$?" != "x0"; then
+ echo "ERROR: createkey ${KEY} failed"
+ printf "%s\n" "${OUTPUT}"
+ false
+ return
+ fi
+
+ # check we can enumerate to level key
+ OUTPUT=$(${NETREG} enumerate ${KEY})
+ if test "x$?" != "x0"; then
+ echo "ERROR: failed to enumerate '${KEY}' after creation"
+ printf "%s\n" "${OUTPUT}"
+ false
+ return
+ fi
+
+ # clear:
+ ${NETREG} deletekey ${KEY} && ${NETREG} deletekey ${KEY2}
+}
+
+test_deletekey_with_subkey()
+{
+ KEY="$1"
+ KEY2=$(dirname ${KEY})
+
+ OUTPUT=$(${NETREG} createkey ${KEY})
+ if test "x$?" != "x0"; then
+ printf "%s\n" "${OUTPUT}"
+ false
+ return
+ fi
+
+ OUTPUT=$(${NETREG} deletekey ${KEY2})
+
+ if test "x$?" = "x0"; then
+ echo "ERROR: delete of key with subkey succeeded"
+ echo "output:"
+ printf "%s\n" "$OUTPUT"
+ false
+ return
+ fi
+
+ ${NETREG} deletekey ${KEY} && ${NETREG} deletekey ${KEY2}
+}
+
+test_setvalue()
+{
+ KEY="$1"
+ VALNAME="${2#_}"
+ VALTYPE="$3"
+ VALVALUE="$4"
+
+ OUTPUT=$(test_createkey ${KEY})
+ if test "x$?" != "x0"; then
+ printf "%s\n" "${OUTPUT}"
+ false
+ return
+ fi
+
+ OUTPUT=$(${NETREG} setvalue ${KEY} "${VALNAME}" ${VALTYPE} ${VALVALUE})
+ if test "x$?" != "x0"; then
+ echo "ERROR: failed to set value testval in key ${KEY}"
+ printf "%s\n" "${OUTPUT}"
+ false
+ return
+ fi
+
+ OUTPUT=$(${NETREG} getvalueraw ${KEY} "${VALNAME}")
+ if test "x$?" != "x0"; then
+ echo "ERROR: failure calling getvalueraw for key ${KEY}"
+ echo output:
+ printf "%s\n" "${OUTPUT}"
+ false
+ return
+ fi
+
+ if test "x${OUTPUT}" != "x${VALVALUE}"; then
+ echo "ERROR: failure retrieving value ${VALNAME} for key ${KEY}"
+ printf "expected: %s\ngot: %s\n" "${VALVALUE}" "${OUTPUT}"
+ false
+ return
+ fi
+
+}
+
+test_deletevalue()
+{
+ KEY="$1"
+ VALNAME="${2#_}"
+
+ ${NETREG} deletevalue ${KEY} "${VALNAME}"
+}
+
+test_deletevalue_nonexisting()
+{
+ KEY="$1"
+ VALNAME="${2#_}"
+
+ ${NETREG} deletevalue ${KEY} "${VALNAME}"
+ if test "x$?" = "x0"; then
+ echo "ERROR: succeeded deleting value ${VALNAME}"
+ false
+ else
+ true
+ fi
+}
+
+test_setvalue_twice()
+{
+ KEY="$1"
+ VALNAME="${2#_}"
+ VALTYPE1="$3"
+ VALVALUE1="$4"
+ VALTYPE2="$5"
+ VALVALUE2="$6"
+
+ OUTPUT=$(test_setvalue ${KEY} _"${VALNAME}" ${VALTYPE1} ${VALVALUE1})
+ if test "x$?" != "x0"; then
+ echo "ERROR: first setvalue call failed"
+ printf "%s\n" "$OUTPUT"
+ false
+ return
+ fi
+
+ ${NETREG} setvalue ${KEY} "${VALNAME}" ${VALTYPE2} ${VALVALUE2}
+}
+
+testit "enumerate HKLM" \
+ test_enumerate HKLM ||
+ failed=$(expr $failed + 1)
+
+testit "enumerate nonexisting hive" \
+ test_enumerate_nonexisting XYZ ||
+ failed=$(expr $failed + 1)
+
+testit "enumerate without key" \
+ test_enumerate_no_key ||
+ failed=$(expr $failed + 1)
+
+# skip getsd test for registry currently: it fails
+if test "x${RPC}" != "xrpc"; then
+ testit "getsd HKLM" \
+ test_getsd HKLM ||
+ failed=$(expr $failed + 1)
+fi
+
+testit "create existing HKLM" \
+ test_create_existing ||
+ failed=$(expr $failed + 1)
+
+testit "create key" \
+ test_createkey HKLM/testkey ||
+ failed=$(expr $failed + 1)
+
+testit "delete key" \
+ test_deletekey HKLM/testkey ||
+ failed=$(expr $failed + 1)
+
+testit "delete^2 key" \
+ test_deletekey_nonexisting HKLM/testkey ||
+ failed=$(expr $failed + 1)
+
+testit "enumerate nonexisting key" \
+ test_enumerate_nonexisting HKLM/testkey ||
+ failed=$(expr $failed + 1)
+
+testit "create key with subkey" \
+ test_createkey_with_subkey HKLM/testkey/subkey ||
+ failed=$(expr $failed + 1)
+
+testit "delete key with subkey" \
+ test_deletekey_with_subkey HKLM/testkey/subkey ||
+ failed=$(expr $failed + 1)
+
+testit "set value" \
+ test_setvalue HKLM/testkey _testval sz moin ||
+ failed=$(expr $failed + 1)
+
+testit "delete value" \
+ test_deletevalue HKLM/testkey _testval ||
+ failed=$(expr $failed + 1)
+
+testit "delete nonexisting value" \
+ test_deletevalue_nonexisting HKLM/testkey _testval ||
+ failed=$(expr $failed + 1)
+
+testit "set value to different type" \
+ test_setvalue_twice HKLM/testkey testval sz moin dword 42 ||
+ failed=$(expr $failed + 1)
+
+testit "set default value" \
+ test_setvalue HKLM/testkey _"" sz 42 ||
+ failed=$(expr $failed + 1)
+
+testit "delete default value" \
+ test_deletevalue HKLM/testkey _"" ||
+ failed=$(expr $failed + 1)
+
+testit "delete nonexisting default value" \
+ test_deletevalue_nonexisting HKLM/testkey _"" ||
+ failed=$(expr $failed + 1)
+
+testit "delete key with value" \
+ test_deletekey HKLM/testkey ||
+ failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_net_registry_check.sh b/source3/script/tests/test_net_registry_check.sh
new file mode 100755
index 0000000..cb0ca17
--- /dev/null
+++ b/source3/script/tests/test_net_registry_check.sh
@@ -0,0 +1,145 @@
+#!/bin/sh
+#
+# Blackbox tests for the "net registry check" command.
+#
+# Copyright (C) 2011 Björn Baumbach <bb@sernet.de>
+
+if [ $# -lt 5 ]; then
+ echo "Usage: test_net_registry_check.sh SCRIPTDIR SERVERCONFFILE NET CONFIGURATION DBWRAP_TOOL"
+ exit 1
+fi
+
+SCRIPTDIR="$1"
+SERVERCONFFILE="$2"
+NET="$3"
+CONFIGURATION="$4"
+DBWRAP_TOOL="$5 --persistent"
+
+NET="$VALGRIND ${NET:-$BINDIR/net} $CONFIGURATION"
+
+NETREG="${NET} registry"
+REGORIG="$(grep 'state directory = ' $SERVERCONFFILE | sed 's/[^=]*=//')/registry.tdb"
+REG=$REGORIG.wip
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+# run registry check and filter allowed errors
+regcheck()
+{
+ ALLOWEDERR="Check database:|INFO: version ="
+ ERRSTR=$(${NETREG} check $REG "$@" 2>&1 | egrep -v "$ALLOWEDERR")
+}
+
+# try to repair registry
+regrepair()
+{
+ regcheck -a
+}
+
+# check if $ERRSTR contains expected error
+checkerr()
+{
+ EXPERR=$1
+
+ ERRCNT=$(echo "$ERRSTR" | grep "$EXPERR" | wc -l)
+ return $ERRCNT
+}
+
+regchecknrepair()
+{
+ EXPERR="$1"
+ EXPERRCNT="$2"
+
+ regcheck
+ checkerr "$EXPERR"
+ test "$?" -eq "$ERRCNT" || {
+ echo "Expected $EXPERRCNT of error $EXPERR. Received $ERRCNT"
+ return 1
+ }
+
+ regrepair
+ regcheck
+ test "x$ERRSTR" = "x" || {
+ echo "Error: Can't repair database"
+ return 1
+ }
+}
+
+test_simple()
+(
+ ERRSTR=""
+ cp $REGORIG $REG
+
+ regcheck
+ test "x$ERRSTR" = "x" || {
+ echo $ERRSTR
+ return 1
+ }
+)
+
+test_damage()
+{
+ diff $REGORIG $REG
+}
+
+test_duplicate()
+(
+ ERRSTR=""
+ $DBWRAP_TOOL $REG store 'HKLM/SOFTWARE' hex '02000000534F4654574152450053595354454D00'
+
+ regchecknrepair "Duplicate subkeylist" 1
+)
+
+test_slashes()
+(
+ ERRSTR=""
+ $DBWRAP_TOOL $REG store 'HKLM/SOFTWARE' hex '02000000534F4654574152450053595354454D00'
+
+ regchecknrepair "Unnormal key:" 1
+)
+
+test_uppercase()
+(
+ ERRSTR=""
+ $DBWRAP_TOOL $REG store 'HKLM\Software' hex '02000000534F4654574152450053595354454D00'
+
+ regchecknrepair "Unnormal key:" 1
+)
+
+test_strangeletters()
+(
+ ERRSTR=""
+ $DBWRAP_TOOL $REG store 'HKLM\SOFTWARE' hex '02000000534F4654574FABFABFABFAB354454D00'
+
+ regchecknrepair "Conversion error: Incomplete multibyte sequence" 1
+)
+
+testit "simple" \
+ test_simple ||
+ failed=$(expr $failed + 1)
+
+testit "damages_registry" \
+ test_damage ||
+ failed=$(expr $failed + 1)
+
+testit "duplicate" \
+ test_duplicate ||
+ failed=$(expr $failed + 1)
+
+testit "slashes" \
+ test_slashes ||
+ failed=$(expr $failed + 1)
+
+testit "uppercase" \
+ test_uppercase ||
+ failed=$(expr $failed + 1)
+
+#Can't repair this atm
+#testit "strangeletters" \
+# test_strangeletters || \
+# failed=`expr $failed + 1`
+
+testok $0 $failed
diff --git a/source3/script/tests/test_net_registry_import.sh b/source3/script/tests/test_net_registry_import.sh
new file mode 100755
index 0000000..cca566f
--- /dev/null
+++ b/source3/script/tests/test_net_registry_import.sh
@@ -0,0 +1,192 @@
+#!/bin/sh
+
+if [ $# -lt 4 ]; then
+ cat <<EOF
+Usage: test_net_registry_import.sh SERVER LOCAL_PATH USERNAME PASSWORD
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+LOCAL_PATH="$2"
+USERNAME="$3"
+PASSWORD="$4"
+shift 4
+ADDARGS="$@"
+
+failed=0
+
+samba_net="$BINDIR/net"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+test_net_registry_import()
+{
+
+ #
+ # Expect:
+ # Found Byte Order Mark for : UTF-16LE
+ #
+ cmd='$VALGRIND $samba_net rpc registry import $LOCAL_PATH/case3b45ccc3b.dat -S$SERVER -U$USERNAME%$PASSWORD $ADDARGS'
+
+ eval echo "$cmd"
+ out=$(eval $cmd 2>&1)
+ ret=$?
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "command failed with output $ret"
+ false
+ return
+ fi
+
+ echo "$out" | grep 'Found Byte Order Mark for : UTF-16LE'
+ ret=$?
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "$samba_net rpc registry import $LOCAL_PATH/case3b45ccc3b.dat failed - should get 'Found Byte Order Mark for : UTF-16LE'"
+ false
+ return
+ fi
+
+ #
+ # Expect:
+ # reg_parse_fd: smb_iconv error in file at line 0: <bf><77><d4><41>
+ #
+ cmd='$VALGRIND $samba_net rpc registry import $LOCAL_PATH/casecbe8c2427.dat -S$SERVER -U$USERNAME%$PASSWORD $ADDARGS'
+
+ eval echo "$cmd"
+ out=$(eval $cmd 2>&1)
+ ret=$?
+
+ if [ $? != 0 ]; then
+ echo "$out"
+ echo "command failed with output $ret"
+ false
+ return
+ fi
+
+ echo "$out" | grep 'reg_parse_fd: smb_iconv error in file at line 0: <bf><77><d4><41>'
+ ret=$?
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "$samba_net rpc registry import $LOCAL_PATH/case3b45ccc3b.dat failed - should get 'reg_parse_fd: smb_iconv error in file at line 0: <bf><77><d4><41>'"
+ false
+ return
+ fi
+
+ #
+ # For test3.dat, the parse of the first part of the file is successful,
+ # but fails on upload as we're writing to an unwriteable registry.
+ # Expect:
+ # setval ProductType failed: WERR_REGISTRY_IO_FAILED
+ # reg_parse_fd: reg_parse_line line 21 fail -2
+ # This counts as a success test as the file is parsed, but
+ # the upload failed.
+ #
+ cmd='$VALGRIND $samba_net rpc registry import $LOCAL_PATH/regtest3.dat -S$SERVER -U$USERNAME%$PASSWORD $ADDARGS'
+
+ eval echo "$cmd"
+ out=$(eval $cmd 2>&1)
+ ret=$?
+
+ if [ $? != 0 ]; then
+ echo "$out"
+ echo "command failed with output $ret"
+ false
+ return
+ fi
+
+ echo "$out" | grep 'setval ProductType failed: WERR_REGISTRY_IO_FAILED'
+ ret=$?
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "$samba_net rpc registry import $LOCAL_PATH/regtest3.dat failed - should get 'setval ProductType failed: WERR_REGISTRY_IO_FAILED'"
+ false
+ return
+ fi
+
+ echo "$out" | grep 'reg_parse_fd: reg_parse_line 20 fail -2'
+ ret=$?
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "$samba_net rpc registry import $LOCAL_PATH/regtest3.dat failed - should get 'reg_parse_fd: reg_parse_line 20 fail -2'"
+ false
+ return
+ fi
+
+ true
+ return
+}
+
+###########################################################
+# Check net rpc registry import doesn't crash
+###########################################################
+
+rm -f $LOCAL_PATH/case3b45ccc3b.dat
+rm -f $LOCAL_PATH/casecbe8c2427.dat
+rm -f $LOCAL_PATH/regtest3.dat
+
+# Create test cases
+
+base64 -d <<'EOF' | gunzip -c >$LOCAL_PATH/case3b45ccc3b.dat
+H4sIAODLjlwCA/v/L5whkyGPIYUhn6GcoZhBgSGIIZUhHShWzFDCUMRQCRRxBcpmAnn5QL4CQxhQ
+vggomwnk5wH5pgx6DAZAyMvABcbRDB4M3kA9kQzxDD4M/gzODI5AOp7BF0g7A+U8GfyAsjEMwUAV
+wQwhQLYvkOfMUPqRUvDw4yAHnz6OgsELgGlYh8EYCHXA6RnENmLIgbJNGZLh4jEMvEWRee8eXl8u
+//f8N9vK5cVVXP9v2rB+/qYw+3xko5Su8jSiLZ0zwJ4GAO4s/cYABAAA
+EOF
+
+base64 -d <<'EOF' | gunzip -c >$LOCAL_PATH/casecbe8c2427.dat
+H4sIALjPjlwCA2NwZfBliGFwZihlKALCVIY8hhIgLx9MFwHpHIZgoGgJUA2ILmIoY8hkSAayioEi
+OQyJQHW5YLIcqLaIIRsoXgLklwBVgcyIYSgA8oqAOBdsCsiEYoZYBl4GLgYlsG2JDElAc1KB6kCm
+ZYLtTWWoAJIgncVACDE5BajeFkjCeFYMBijQEIuZxUCcDPZZJkNJ3f7yK45/V3S8epR2I14uf+4W
+ee+dz0RXshv4SHxzff2XJYbx0pWaEs+ul5XKF9hlFIu4RG73Lf3rOXHW3NxpuvVnE9Xk7zxv2p3I
+tlLtWjY/i1HIGhdpLy/Gub9nH5jLd/rqdYfv2uumzgq7PIldPY3Labru/65Q/nLJh1oBk/0tT2v2
+eUdbzFg0NfPmamFH421aJxMPhnr7X+y0iRdSX+ex+IJ0Yaf0ahV5440Wj7cbK/jkbSjcNdvpR+WN
+/5Knnn8PjvvD9O/Ws4pXUqG3lbdFrf1846zzcTOFW8yhB3QNZRP6TjOsu1rDvIaHZVfMyYd1Mhev
+ik/a5m36Y85+y63pPmtXb8nOU5Zd0qK0yVJK8a27WqKHSOKaS7wpwULu1TsM94bVGD3xviR0u1Il
+rFHoxeUrm2+6Ke4x2SGitD912ZGfLcmG0xiyIn+bmx0+s+dbXuT8xfl+CgL168yNzYxCgsviz/46
+b7746Wnh8zXZHDof6/yDyxdf31JkzN5YVP4kf/vkvrS1ioauYemc3RIt7znZQvpOy7XO8VU5+KeP
+VXKPXrzr+nMv/v5wkpA7v2TukgqHZ4e6i+Zsjfny6vHdg7+mLFjg/th4m55ppH75HYcLjEa/U4/w
+SeXMTuVXablo/fmJnlPA6T12usz8nBGVKbVzTNqrTJ6d/+Y0y2bGc5MlzgnymUVq/9/PyZ2QxZvR
+4WyR810zd32X5ncJRd/y7VNCd746G/jTTFLTJfHx86dVtlkL02zeCJeYsmkdrXVhtpl7Y5OOyJcD
+DJXA9JPJkA5MT8YMOuA0psNgBExRMLYZgwkSOxnM1kdiG6CQkNTpD0zXGeBc4AJMx7nQFF8MTttA
+8f8VDBoM5gya4NRNtgN0zczNjM1MDCwMLcwMTCwtLYxNjLE4wK5pwpebAAJ05DUABAAA
+EOF
+
+base64 -d <<'EOF' >$LOCAL_PATH/regtest3.dat
+UkVHRURJVDQKCltIS0VZX0xPQ0FMX01BQ0hJTkVdCgpbSEtFWV9MT0NBTF9NQUNISU5FXFNPRlRX
+QVJFXQoKW0hLRVlfTE9DQUxfTUFDSElORVxTT0ZUV0FSRVxNaWNyb3NvZnRdCgpbSEtFWV9MT0NB
+TF9NQUNISU5FXFNPRlRXQVJFXE1pY3Jvc29mdFxXaW5kb3dzIE5UXQoKW0hLRVlfTE9DQUxfTUFD
+SElORVxTT0ZUV0FSRVxNaWNyb3NvZnRcV2luZG93cyBOVFxDdXJyZW50VmVyc2lvbl0KIkN1cnJl
+bnRWZXJzaW9uIj0iNi4xIgoKW0hLRVlfTE9DQUxfTUFDSElORVxTWVNURU1dCgpbSEtFWV9MT0NB
+TF9NQUNISU5FXFNZU1RFTVxDdXJyZW50Q29udHJvbFNldF0KCltIS0VZX0xPQ0FMX01BQ0hJTkVc
+U1lTVEVNXEN1cnJlbnRDb250cm9sU2V0XENvbnRyb2xdCgpbSEtFWV9MT0NBTF9NQUNISU5FXFNZ
+U1RFTVxDdXJyZW50Q29udHJvbFNldFxDb250cm9sXFByb2R1Y3RPcHRpb25zXQoiUHJvZHVjdFR5
+cGUiPSJMYW5tYW5OVCIKCltIS0VZX0xPQ0FMX01BQ0hJTkVcU1lTVEVNXEN1cnJlbnRDb250cm9s
+U2V0XENvbnRyb2xcUHJpbnRdCgpbSEtFWV9MT0NBTF9NQUNISU5FXFNZU1RFTVxDdXJyZW50Q29u
+dHJvbFNldFxDb250cm9sXFRlcm1pbmFsIFNlcnZlcl0KCltIS0VZX0xPQ0FMX01BQ0hJTkVcU1lT
+VEVNXQoKW0hLRVlfTE9DQUxfTUFDSElORVxTWVNURU1cQ3VycmVudENvbnRyb2xTZXRdCgpbSEtF
+WV9MT0NBTF9NQUNISU5FXFNZU1RFTVxDdXJyZW50Q29udHJvbFNldFxTZXJ2aWNlc10KCltIS0VZ
+X0xPQ0FMX01BQ0hJTkVcU1lTVEVNXEN1cnJlbnRDb250cm9sU2V0XFNlcnZpY2VzXE5ldGxvZ29u
+XQoKW0hLRVlfTE9DQUxfTUFDSElORVxTWVNURU1cQ3VycmVudENvbnRyb2xTZXRcU2VydmljZXNc
+TmV0bG9nb25cUGFyYW1ldGVyc10KIlJlZnVzZVBhc3N3b3JkQ2hhbmdlIj1kd29yZDowMDAwMDAw
+MAoKW0hLRVlfTE9DQUxfTUFDSElORVxTWVNURU1cQ3VycmVudENvbnRyb2xTZXRcU2VydmljZXNc
+QWxlcnRlcl0KCltIS0VZX0xPQ0FMX01BQ0hJTkVcU1lTVEVNXEN1cnJlbnRDb250cm9sU2V0XA==
+EOF
+
+testit "Test net rpc registry import" \
+ test_net_registry_import ||
+ failed=$(expr $failed + 1)
+
+# Clean up test cases.
+rm -f $LOCAL_PATH/case3b45ccc3b.dat
+rm -f $LOCAL_PATH/casecbe8c2427.dat
+rm -f $LOCAL_PATH/regtest3.dat
+
+testok $0 $failed
diff --git a/source3/script/tests/test_net_registry_roundtrip.sh b/source3/script/tests/test_net_registry_roundtrip.sh
new file mode 100755
index 0000000..e1974c2
--- /dev/null
+++ b/source3/script/tests/test_net_registry_roundtrip.sh
@@ -0,0 +1,158 @@
+#!/bin/sh
+#
+# Blackbox test for net conf/registry roundtrips.
+#
+# Copyright (C) 2010 Gregor Beck <gbeck@sernet.de>
+# Copyright (C) 2011 Michael Adam <obnox@samba.org>
+
+if [ $# -lt 3 ]; then
+ cat <<EOF
+Usage: test_net_registry_roundtrip.sh SCRIPTDIR SERVERCONFFILE NET CONFIGURATION RPC
+EOF
+ exit 1
+fi
+
+SCRIPTDIR="$1"
+SERVERCONFFILE="$2"
+NET="$3"
+CONFIGURATION="$4"
+RPC="$5"
+
+NET="$VALGRIND ${NET} $CONFIGURATION"
+
+if test "x${RPC}" = "xrpc"; then
+ NETCMD="${NET} -U${USERNAME}%${PASSWORD} -I ${SERVER_IP} rpc"
+else
+ NETCMD="${NET}"
+fi
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+#
+# List of parameters to skip when importing configuration files:
+# They are forbidden in the registry and would lead import to fail.
+#
+SED_INVALID_PARAMS="{
+s/state directory/;&/g
+s/lock directory/;&/g
+s/lock dir/;&/g
+s/config backend/;&/g
+s/include/;&/g
+}"
+
+REGPATH="HKLM\Software\Samba"
+
+conf_roundtrip_step()
+{
+ echo "CMD: $*" >>$LOG
+ "$@" 2>>$LOG
+ RC=$?
+ echo "RC: $RC" >>$LOG
+ test "x$RC" = "x0" || {
+ echo "ERROR: $* failed (RC=$RC)" | tee -a $LOG
+ }
+ return $RC
+ # echo -n .
+}
+
+LOGDIR_PREFIX="conf_roundtrip"
+
+conf_roundtrip()
+(
+ DIR=$(mktemp -d ${PREFIX}/${LOGDIR_PREFIX}_XXXXXX)
+ LOG=$DIR/log
+
+ echo conf_roundtrip $1 >$LOG
+
+ sed -e "$SED_INVALID_PARAMS" $1 >$DIR/conf_in
+
+ conf_roundtrip_step $NETCMD conf drop
+ test "x$?" = "x0" || {
+ return 1
+ }
+
+ test -z "$($NETCMD conf list)" 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: conf drop failed" | tee -a $LOG
+ return 1
+ fi
+
+ conf_roundtrip_step $NETCMD conf import $DIR/conf_in
+ test "x$?" = "x0" || {
+ return 1
+ }
+
+ conf_roundtrip_step $NETCMD conf list >$DIR/conf_exp
+ test "x$?" = "x0" || {
+ return 1
+ }
+
+ grep "\[global\]" $DIR/conf_exp >/dev/null 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: conf import => conf export failed" | tee -a $LOG
+ return 1
+ fi
+
+ conf_roundtrip_step $NETCMD -d10 registry export $REGPATH $DIR/conf_exp.reg
+ test "x$?" = "x0" || {
+ return 1
+ }
+
+ conf_roundtrip_step $NETCMD conf drop
+ test "x$?" = "x0" || {
+ return 1
+ }
+
+ test -z "$($NETCMD conf list)" 2>>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: conf drop failed" | tee -a $LOG
+ return 1
+ fi
+
+ conf_roundtrip_step $NETCMD registry import $DIR/conf_exp.reg
+ test "x$?" = "x0" || {
+ return 1
+ }
+
+ conf_roundtrip_step $NETCMD conf list >$DIR/conf_out
+ test "x$?" = "x0" || {
+ return 1
+ }
+
+ diff -q $DIR/conf_out $DIR/conf_exp >>$LOG
+ if [ "$?" = "1" ]; then
+ echo "ERROR: registry import => conf export failed" | tee -a $LOG
+ return 1
+ fi
+
+ conf_roundtrip_step $NETCMD registry export $REGPATH $DIR/conf_out.reg
+ test "x$?" = "x0" || {
+ return 1
+ }
+
+ diff -q $DIR/conf_out.reg $DIR/conf_exp.reg >>$LOG
+ if [ "$?" = "1" ]; then
+ echo "Error: registry import => registry export failed" | tee -a $LOG
+ return 1
+ fi
+ rm -r $DIR
+)
+
+CONF_FILES=$SERVERCONFFILE
+
+# remove old logs:
+for OLDDIR in $(find ${PREFIX} -type d -name "${LOGDIR_PREFIX}_*"); do
+ echo "removing old directory ${OLDDIR}"
+ rm -rf ${OLDDIR}
+done
+
+for conf_file in $CONF_FILES; do
+ testit "conf_roundtrip $conf_file" \
+ conf_roundtrip $conf_file ||
+ failed=$(expr $failed + 1)
+done
+
+testok $0 $failed
diff --git a/source3/script/tests/test_net_rpc_join.sh b/source3/script/tests/test_net_rpc_join.sh
new file mode 100755
index 0000000..319d044
--- /dev/null
+++ b/source3/script/tests/test_net_rpc_join.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+if [ $# -lt 4 ]; then
+ cat <<EOF
+Usage: test_net_rpc_join.sh USERNAME PASSWORD SERVER PREFIX
+EOF
+ exit 1
+fi
+
+USERNAME="$1"
+PASSWORD="$2"
+SERVER="$3"
+PREFIX="$4"
+shift 4
+ADDARGS="$*"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+mkdir -p $PREFIX/private
+testit "net_rpc_join" $VALGRIND $BINDIR/net rpc join -S $SERVER --option=netbiosname=netrpcjointest --option=domainlogons=yes --option=privatedir=$PREFIX/private -U$USERNAME%$PASSWORD $ADDARGS || failed=$(expr $failed + 1)
+testit "net_rpc_testjoin" $VALGRIND $BINDIR/net rpc testjoin -S $SERVER --option=netbiosname=netrpcjointest --option=domainlogons=yes --option=privatedir=$PREFIX/private $ADDARGS || failed=$(expr $failed + 1)
+testit "net_rpc_changetrustpw" $VALGRIND $BINDIR/net rpc changetrustpw -S $SERVER --option=netbiosname=netrpcjointest --option=domainlogons=yes --option=privatedir=$PREFIX/private $ADDARGS || failed=$(expr $failed + 1)
+testit "net_rpc_testjoin2" $VALGRIND $BINDIR/net rpc testjoin -S $SERVER --option=netbiosname=netrpcjointest --option=domainlogons=yes --option=privatedir=$PREFIX/private $ADDARGS || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_net_rpc_join_creds.sh b/source3/script/tests/test_net_rpc_join_creds.sh
new file mode 100755
index 0000000..24376ef
--- /dev/null
+++ b/source3/script/tests/test_net_rpc_join_creds.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+if [ $# -lt 5 ]; then
+ cat <<EOF
+Usage: test_net_rpc_join_creds.sh DOMAIN USERNAME PASSWORD SERVER PREFIX
+EOF
+ exit 1
+fi
+
+DOMAIN="$1"
+USERNAME="$2"
+PASSWORD="$3"
+SERVER="$4"
+PREFIX="$5"
+shift 5
+ADDARGS="$*"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+mkdir -p $PREFIX/private
+# Test using a credentials file.
+credsfile=$PREFIX/creds.$$
+printf '%s\n' "username=$USERNAME" "password=$PASSWORD" "domain=$DOMAIN" >"$credsfile"
+testit "net_rpc_join_creds" $VALGRIND $BINDIR/net rpc join -S $SERVER --option=netbiosname=netrpcjointest --option=domainlogons=yes --option=privatedir=$PREFIX/private -A"$credsfile" $ADDARGS || failed=$(expr $failed + 1)
+testit "net_rpc_testjoin_creds" $VALGRIND $BINDIR/net rpc testjoin -S $SERVER --option=netbiosname=netrpcjointest --option=domainlogons=yes --option=privatedir=$PREFIX/private $ADDARGS || failed=$(expr $failed + 1)
+testit "net_rpc_changetrustpw_creds" $VALGRIND $BINDIR/net rpc changetrustpw -S $SERVER --option=netbiosname=netrpcjointest --option=domainlogons=yes --option=privatedir=$PREFIX/private $ADDARGS || failed=$(expr $failed + 1)
+testit "net_rpc_testjoin2_creds" $VALGRIND $BINDIR/net rpc testjoin -S $SERVER --option=netbiosname=netrpcjointest --option=domainlogons=yes --option=privatedir=$PREFIX/private $ADDARGS || failed=$(expr $failed + 1)
+rm -f $credsfile
+
+testok $0 $failed
diff --git a/source3/script/tests/test_net_rpc_oldjoin.sh b/source3/script/tests/test_net_rpc_oldjoin.sh
new file mode 100755
index 0000000..d650ead
--- /dev/null
+++ b/source3/script/tests/test_net_rpc_oldjoin.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+if [ $# -lt 3 ]; then
+ cat <<EOF
+Usage: test_net_rpc_oldjoin.sh SERVER PREFIX SMB_CONF_PATH
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+PREFIX="$2"
+SMB_CONF_PATH="$3"
+shift 3
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+maccount="OLDJOINTEST"
+privatedir="$PREFIX/private"
+
+OPTIONS="--configfile $SMB_CONF_PATH --option=netbiosname=$maccount --option=security=domain --option=domainlogons=no --option=privatedir=$privatedir"
+
+test_smbpasswd()
+{
+ account=$1
+
+ echo "set password with smbpasswd"
+
+ cmd='UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 $VALGRIND $BINDIR/smbpasswd -L -c $SMB_CONF_PATH -a -m "$account"'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret -ne 0 ]; then
+ echo "Failed to change user password $user"
+ return 1
+ fi
+}
+
+testit "mkdir -p $privatedir" mkdir -p $privatedir || failed=$(expr $failed + 1)
+testit "smbpasswd -a -m" \
+ test_smbpasswd $maccount ||
+ failed=$(expr $failed + 1)
+testit "net_rpc_oldjoin" $VALGRIND $BINDIR/net rpc oldjoin -S $SERVER $OPTIONS || failed=$(expr $failed + 1)
+testit "net_rpc_testjoin1" $VALGRIND $BINDIR/net rpc testjoin -S $SERVER $OPTIONS || failed=$(expr $failed + 1)
+testit "net_rpc_changetrustpw" $VALGRIND $BINDIR/net rpc changetrustpw -S $SERVER $OPTIONS || failed=$(expr $failed + 1)
+testit "net_rpc_testjoin2" $VALGRIND $BINDIR/net rpc testjoin -S $SERVER $OPTIONS || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_net_rpc_share_allowedusers.sh b/source3/script/tests/test_net_rpc_share_allowedusers.sh
new file mode 100755
index 0000000..3365813
--- /dev/null
+++ b/source3/script/tests/test_net_rpc_share_allowedusers.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+if [ $# -lt 4 ]; then
+ cat <<EOF
+Usage: test_net_rpc_share_allowedusers.sh SERVER USERNAME PASSWORD PREFIX
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+USERNAME="$2"
+PASSWORD="$3"
+PREFIX="$4"
+shift 4
+ADDARGS="$*"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+mkdir -p $PREFIX/private
+net=$BINDIR/net
+# Check for the SID for group "Everyone" as a basic test things are working.
+testit_grep "net_usersidlist" '^ S-1-1-0$' $VALGRIND $net usersidlist $ADDARGS || failed=$(expr $failed + 1)
+# Check "print$" share is listed by default.
+testit_grep "net_rpc_share_allowedusers" '^print\$$' $net usersidlist | $VALGRIND $net rpc share allowedusers -S$SERVER -U$USERNAME%$PASSWORD $ADDARGS || failed=$(expr $failed + 1)
+# Check "print$" share is listed if we ask for it.
+testit_grep "net_rpc_share_allowedusers" '^print\$$' $net usersidlist | $VALGRIND $net rpc share allowedusers -S$SERVER -U$USERNAME%$PASSWORD $ADDARGS - 'print$' || failed=$(expr $failed + 1)
+# Check user "user1" is allowed to read share "tmp".
+testit_grep "net_rpc_share_allowedusers" '^ user1$' $net usersidlist | $VALGRIND $net rpc share allowedusers -S$SERVER -U$USERNAME%$PASSWORD $ADDARGS || failed=$(expr $failed + 1)
+#
+# Subtle extra test for bug https://bugzilla.samba.org/show_bug.cgi?id=13992
+#
+# '^ user1$' must appear MORE THAN ONCE, as it can read more than one
+# share. The previous test found user1, but only once as the bug only
+# allows reading the security descriptor for one share, and we were
+# unlucky that the first share security descriptor returned allows
+# user1 to read from it.
+#
+subunit_start_test "net_rpc_share_allowedusers"
+multi_userout=$($net usersidlist | $VALGRIND $net rpc share allowedusers -S$SERVER -U$USERNAME%$PASSWORD $ADDARGS)
+num_matches=$(echo "$multi_userout" | grep -c '^ user1$')
+if [ "$num_matches" -gt "1" ]; then
+ subunit_pass_test "net_rpc_share_allowedusers"
+else
+ echo "net_rpc_share_allowedusers only found $num_matches shares readable by user1. Should be greater than one.\n"
+ failed=$(expr $failed + 1)
+ echo "$multi_userout" | subunit_fail_test "net_rpc_share_allowedusers"
+fi
+
+testok $0 $failed
diff --git a/source3/script/tests/test_net_tdb.sh b/source3/script/tests/test_net_tdb.sh
new file mode 100755
index 0000000..abc8786
--- /dev/null
+++ b/source3/script/tests/test_net_tdb.sh
@@ -0,0 +1,104 @@
+#!/bin/sh
+#
+# Test 'net tdb' command.
+#
+# Verify that the command returns the correct information in the
+# expected format. The 'dump' option is tested, but the output is not
+# checked, since the internal data structure could change in the
+# future.
+#
+# Copyright (C) 2017 Christof Schmitt
+
+if [ $# -lt 7 ]; then
+ cat <<EOF
+Usage: $0 SMBCLIENT SERVER SHARE USER PASS CONFIGURATION LOCALPATH LOCKDIR
+EOF
+ exit 1
+fi
+
+SMBCLIENT=$1
+SERVER=$2
+SHARE=$3
+USER=$4
+PASS=$5
+CONFIGURATION=$6
+LOCALPATH=$7
+LOCKDIR=$8
+
+FILENAME=net_tdb_testfile
+
+samba_tdbtool=tdbtool
+if test -x $BINDIR/tdbtool; then
+ samba_tdbtool=$BINDIR/tdbtool
+fi
+
+failed=0
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+touch $LOCALPATH/$FILENAME
+
+printf "open %s\n"'!sleep 10'"\n" ${FILENAME} |
+ $SMBCLIENT //$SERVER/$SHARE -U$USER%$PASS &
+SMBCLIENTPID=$!
+
+# Give smbclient a chance to open the file
+sleep 1
+
+testit "Looking for record key of open file" \
+ $samba_tdbtool $LOCKDIR/locking.tdb hexkeys ||
+ failed=$(expr $failed + 1)
+
+# The assumption here is that only one file is open, so only one
+# record can exist in the database.
+
+# Output of 'tdbtool hexkeys' is in this format:
+#[000] 01 FD 00 00 00 00 00 00 56 02 5C 00 00 00 00 00 ....... V.\....
+#[010] 00 00 00 00 00 00 00 00 .......
+# Select only the hex data, remove space and join every thing together
+key=0x$($samba_tdbtool $LOCKDIR/locking.tdb hexkeys |
+ grep '\[' | cut -c 7-56 | sed -e 's/ //g' | tr -d '\n')
+
+testit "Looking for open file in locking.tdb" \
+ $BINDIR/net $CONFIGURATION tdb locking $key ||
+ failed=$(expr $failed + 1)
+out=$($BINDIR/net $CONFIGURATION tdb locking $key)
+
+out=$($BINDIR/net $CONFIGURATION tdb locking $key |
+ grep 'Share path: ' | sed -e 's/Share path: \+//')
+testit "Verify pathname in output" \
+ test "$out" = "$LOCALPATH" ||
+ failed=$(expr $failed + 1)
+
+out=$($BINDIR/net $CONFIGURATION tdb locking $key |
+ grep 'Name:' | sed -e 's/Name: \+//')
+testit "Verify filename in output" \
+ test "$out" = "$FILENAME" ||
+ failed=$(expr $failed + 1)
+
+out=$($BINDIR/net $CONFIGURATION tdb locking $key |
+ grep 'Number of share modes:' |
+ sed -e 's/Number of share modes: \+//')
+testit "Verify number of share modes in output" \
+ test "$out" = "1" ||
+ failed=$(expr $failed + 1)
+
+testit "Complete record dump" \
+ $BINDIR/net $CONFIGURATION tdb locking $key dump ||
+ failed=$(expr $failed + 1)
+
+$BINDIR/net $CONFIGURATION tdb locking $key dump | grep -q $FILENAME
+RC=$?
+testit "Verify filename in dump output" \
+ test $RC = 0 ||
+ failed=$(expr $failed + 1)
+$BINDIR/net $CONFIGURATION tdb locking $key dump | grep -q $LOCALPATH
+RC=$?
+testit "Verify share path in dump output" \
+ test $RC = 0 ||
+ failed=$(expr $failed + 1)
+
+kill $SMBCLIENTPID
+
+testok $0 $failed
diff --git a/source3/script/tests/test_net_usershare.sh b/source3/script/tests/test_net_usershare.sh
new file mode 100755
index 0000000..bf6334d
--- /dev/null
+++ b/source3/script/tests/test_net_usershare.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+if [ $# -lt 5 ]; then
+ cat <<EOF
+Usage: test_net_usershare.sh SERVER SERVER_IP DOMAIN USERNAME PASSWORD SMBCLIENT <smbclient arguments>
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+SERVER_IP="$2"
+USERNAME="$3"
+PASSWORD="$4"
+smbclient="$5"
+shift 5
+ADDARGS="$@"
+
+failed=0
+
+samba_bindir="$BINDIR"
+samba_net="$samba_bindir/net"
+samba_smbcontrol="$samba_bindir/smbcontrol"
+
+samba_share_dir="$LOCAL_PATH"
+samba_usershare_dir="$samba_share_dir/usershares"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+test_smbclient()
+{
+ name="$1"
+ share="$2"
+ cmd="$3"
+ shift 3
+ echo "test: $name"
+ $VALGRIND $smbclient $CONFIGURATION //$SERVER/$share -c "$cmd" "$@"
+ status=$?
+ if [ x$status = x0 ]; then
+ echo "success: $name"
+ else
+ echo "failure: $name"
+ fi
+ return $status
+}
+
+test_net_usershare()
+{
+ name="$1"
+ cmd="$2"
+ shift
+ shift
+ echo "test: $name"
+ $VALGRIND $samba_net usershare "$cmd" "$@"
+ status=$?
+ if [ x$status = x0 ]; then
+ echo "success: $name"
+ else
+ echo "failure: $name"
+ fi
+ return $status
+}
+
+###########################################################
+# Check if we can add and delete a usershare
+###########################################################
+
+samba_usershare_name="test_usershare_1"
+samba_usershare_path="$samba_usershare_dir/$samba_usershare_name"
+
+testit "create usershare dir for $samba_usershare_name" mkdir --mode=0755 --verbose $samba_usershare_path || failed=$(expr $failed + 1)
+
+test_net_usershare "net usershare add $samba_usershare_name" "add" "$samba_usershare_name" "$samba_usershare_path" "$samba_usershare_name"
+
+test_net_usershare "net usershare info $samba_usershare_name" "info" "$samba_usershare_name"
+
+test_smbclient "smbclient to $samba_usershare_name" "$samba_usershare_name" 'ls' -U$USERNAME%$PASSWORD || failed=$(expr $failed + 1)
+
+# CLEANUP
+test_net_usershare "net usershare delete $samba_usershare_name" "delete" "$samba_usershare_name"
+testit "remove usershare dir for $samba_usershare_name" rm -rf $samba_usershare_path || failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source3/script/tests/test_netfileenum.sh b/source3/script/tests/test_netfileenum.sh
new file mode 100755
index 0000000..d343555
--- /dev/null
+++ b/source3/script/tests/test_netfileenum.sh
@@ -0,0 +1,84 @@
+#!/usr/bin/env bash
+#
+# Test rpcclient netfileenum
+#
+# Copyright (C) 2020 Volker Lendecke
+
+if [ $# -lt 5 ]; then
+ echo Usage: $0 \
+ SMBCLIENT RPCCLIENT NET SERVER SHARE
+ exit 1
+fi
+
+SMBCLIENT="$1"
+shift 1
+RPCCLIENT="$1"
+shift 1
+NET="$1"
+shift 1
+SERVER="$1"
+shift 1
+SHARE="$1"
+shift 1
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+cd $SELFTEST_TMPDIR || exit 1
+
+rm -f smbclient-stdin smbclient-stdout smbclient-stderr
+mkfifo smbclient-stdin smbclient-stdout smbclient-stderr
+
+CLI_FORCE_INTERACTIVE=1
+export CLI_FORCE_INTERACTIVE
+
+${SMBCLIENT} //${SERVER}/${SHARE} ${CONF} -U${USER}%${PASSWORD} \
+ <smbclient-stdin >smbclient-stdout 2>smbclient-stderr &
+CLIENT_PID=$!
+
+sleep 1
+
+exec 100>smbclient-stdin 101<smbclient-stdout 102<smbclient-stderr
+
+# consume the smbclient startup messages
+head -n 1 <&101
+
+FILE=x64
+
+printf "open %s\\n" "$FILE" >&100
+
+sleep 1
+
+testit "Create builtin\\administrators group" \
+ "${NET}" groupmap add \
+ sid=S-1-5-32-544 unixgroup="${USER}"-group type=builtin ||
+ failed=$((failed + 1))
+testit "Add ${USER} to builtin\\administrators" \
+ "${NET}" groupmap addmem S-1-5-32-544 \
+ $("${NET}" lookup name "${USER}" | cut -d' ' -f1) ||
+ failed=$((failed + 1))
+
+"${RPCCLIENT}" "${SERVER}" -U"${USER}"%"${PASSWORD}" -c netfileenum |
+ grep "$FILE"\$
+RC=$?
+testit "netfileenum" test $RC = 0 || failed=$((failed + 1))
+
+kill ${CLIENT_PID}
+rm -f smbclient-stdin smbclient-stdout smbclient-stderr
+
+testit "Remove ${USER} from builtin\\administrators" \
+ "${NET}" groupmap delmem S-1-5-32-544 \
+ $("${NET}" lookup name "${USER}" | cut -d' ' -f1) ||
+ failed=$((failed + 1))
+testit "Remove builtin\\administrators group" \
+ "${NET}" groupmap delete \
+ sid=S-1-5-32-544 ||
+ failed=$((failed + 1))
+
+testok $0 $failed
diff --git a/source3/script/tests/test_nt4_trust.sh b/source3/script/tests/test_nt4_trust.sh
new file mode 100755
index 0000000..b3d6ca6
--- /dev/null
+++ b/source3/script/tests/test_nt4_trust.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+. $incdir/common_test_fns.inc
+
+failed=0
+
+wbinfo="$BINDIR/wbinfo"
+smbclient="$BINDIR/smbclient"
+
+test_trust_wbinfo_m() {
+ i=0
+ # Give the server some time to list trusted domains
+ while [ $i -lt 10 ] ; do
+ $wbinfo -m | grep SAMBA-TEST && return 0
+ sleep 2
+ i=$((i + 1))
+ done
+ return 1
+}
+
+test_trust_smbclient() {
+ $smbclient //$NT4_TRUST_SERVER_IP/tmp -U "$DOMAIN/$DOMAIN_USER%$DOMAIN_USER_PASSWORD" -c quit || return 1
+ return 0
+}
+
+testit "nt4trust_wbinfo_m" test_trust_wbinfo_m || failed=$(expr $failed + 1)
+testit "nt4trust_smbclient" test_trust_smbclient || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_offline.sh b/source3/script/tests/test_offline.sh
new file mode 100755
index 0000000..5e06b1f
--- /dev/null
+++ b/source3/script/tests/test_offline.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+#
+# Blackbox test for the offline VFS module.
+#
+if [ $# -lt 7 ]; then
+ cat <<EOF
+Usage: test_offline SERVER SERVER_IP DOMAIN USERNAME PASSWORD WORKDIR SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER=${1}
+SERVER_IP=${2}
+DOMAIN=${3}
+USERNAME=${4}
+PASSWORD=${5}
+WORKDIR=${6}
+SMBCLIENT=${7}
+shift 7
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+ADDARGS="$*"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+touch $WORKDIR/foo
+
+failed=0
+
+attribs=$($SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/offline" -I $SERVER_IP -c "allinfo foo" | sed -n 's/^attributes:.*(\([^)]*\)).*/\1/p')
+testit "file has offline attribute" test "x$attribs" = "x1000" || failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source3/script/tests/test_old_dirlisting.sh b/source3/script/tests/test_old_dirlisting.sh
new file mode 100755
index 0000000..f50a474
--- /dev/null
+++ b/source3/script/tests/test_old_dirlisting.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# This tests listing directories using the SMBSearch call family
+
+if [ $# -lt 2 ]; then
+ cat <<EOF
+Usage: $0 TIMELIMIT SMBCLIENT
+EOF
+ exit 1
+fi
+
+TIMELIMIT="$1"
+shift
+SMBCLIENT="$VALGRIND $1"
+shift
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+# Make sure we don't loop 100% CPU. A normal dir listing should return
+# in less than 3 seconds. At the point of this commit smbclient -c dir
+# | wc returns 43 lines, so checking for 100 lines should be well
+# enough.
+
+count=$($TIMELIMIT 3 $SMBCLIENT //"$SERVER_IP"/tmpguest -m LANMAN1 -U% \
+ -c dir | wc -l)
+
+testit "listing shares with LANMAN1" test ${count} -le 100 ||
+ failed=$((failed + 1))
diff --git a/source3/script/tests/test_open_eintr.sh b/source3/script/tests/test_open_eintr.sh
new file mode 100755
index 0000000..b40b14d
--- /dev/null
+++ b/source3/script/tests/test_open_eintr.sh
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+#
+# Test smbd handling when open returns EINTR
+#
+# Copyright (C) 2020 Volker Lendecke
+
+if [ $# -lt 5 ]; then
+ echo Usage: test_open_eintr.sh \
+ --configfile=SERVERCONFFILE SMBCLIENT SMBCONTROL SERVER SHARE
+ exit 1
+fi
+
+CONF=$1
+shift 1
+SMBCLIENT=$1
+shift 1
+SMBCONTROL=$1
+shift 1
+SERVER=$1
+shift 1
+SHARE=$1
+shift 1
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+error_inject_conf=$(dirname ${SERVERCONFFILE})/error_inject.conf
+>${error_inject_conf}
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+cd $SELFTEST_TMPDIR || exit 1
+
+rm -f smbclient-stdin smbclient-stdout smbclient-stderr
+mkfifo smbclient-stdin smbclient-stdout smbclient-stderr
+
+CLI_FORCE_INTERACTIVE=1
+export CLI_FORCE_INTERACTIVE
+
+${SMBCLIENT} //${SERVER}/${SHARE} ${CONF} -U${USER}%${PASSWORD} \
+ <smbclient-stdin >smbclient-stdout 2>smbclient-stderr &
+CLIENT_PID=$!
+
+sleep 1
+
+exec 100>smbclient-stdin 101<smbclient-stdout 102<smbclient-stderr
+
+# consume the smbclient startup messages
+head -n 1 <&101
+
+echo "error_inject:openat = EINTR" >${error_inject_conf}
+${SMBCONTROL} ${CONF} 0 reload-config
+
+sleep 1
+>${error_inject_conf}
+
+echo 'get badnames/blank.txt -' >&100
+
+sleep 1
+
+>${error_inject_conf}
+${SMBCONTROL} ${CONF} 0 reload-config
+
+head -n 1 <&102 | grep 'getting file' >/dev/null
+GREP_RET=$?
+
+kill ${CLIENT_PID}
+rm -f smbclient-stdin smbclient-stdout smbclient-stderr
+
+testit "Verify that we could get the file" \
+ test $GREP_RET -eq 0 || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_preserve_case.sh b/source3/script/tests/test_preserve_case.sh
new file mode 100755
index 0000000..c9ca79a
--- /dev/null
+++ b/source3/script/tests/test_preserve_case.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+#
+# Blackbox test for share with preserve case options
+#
+# https://bugzilla.samba.org/show_bug.cgi?id=10650
+
+if [ $# -lt 6 ]; then
+ cat <<EOF
+Usage: test_preserve_case.sh SERVER DOMAIN USERNAME PASSWORD PREFIX SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER=$1
+DOMAIN=$2
+USERNAME=$3
+PASSWORD=$4
+PREFIX=$5
+smbclient=$6
+if [ $# -gt 6 ]; then
+ PROTOCOL_LIST=$7
+ shift 7
+else
+ PROTOCOL_LIST="NT1 SMB2 SMB3"
+ shift 6
+fi
+failed=0
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+cd $SELFTEST_TMPDIR || exit 1
+
+test_smbclient()
+{
+ name="$1"
+ share="$2"
+ cmd="$3"
+ shift
+ shift
+ subunit_start_test "$name"
+ output=$($VALGRIND $smbclient //$SERVER/$share -c "$cmd" "$@" 2>&1)
+ status=$?
+ if [ x$status = x0 ]; then
+ subunit_pass_test "$name"
+ else
+ echo "$output" | subunit_fail_test "$name"
+ fi
+ return $status
+}
+
+SHARE="lowercase"
+
+for PROTOCOL in $PROTOCOL_LIST; do
+ test_smbclient "Test lowercase ls 1 ($PROTOCOL)" $SHARE "ls 1" -U$USERNAME%$PASSWORD -m$PROTOCOL || failed=$(expr $failed + 1)
+ test_smbclient "Test lowercase get 1 ($PROTOCOL)" $SHARE "get 1 LOCAL_1" -U$USERNAME%$PASSWORD -m$PROTOCOL || failed=$(expr $failed + 1)
+ rm -f LOCAL_1
+
+ test_smbclient "Test lowercase ls A ($PROTOCOL)" $SHARE "ls A" -U$USERNAME%$PASSWORD -m$PROTOCOL || failed=$(expr $failed + 1)
+ test_smbclient "Test lowercase get A ($PROTOCOL)" $SHARE "get A LOCAL_A" -U$USERNAME%$PASSWORD -m$PROTOCOL || failed=$(expr $failed + 1)
+ rm -f LOCAL_A
+
+ test_smbclient "Test lowercase ls z ($PROTOCOL)" $SHARE "ls z" -U$USERNAME%$PASSWORD -m$PROTOCOL || failed=$(expr $failed + 1)
+ test_smbclient "Test lowercase get z ($PROTOCOL)" $SHARE "get z LOCAL_Z" -U$USERNAME%$PASSWORD -m$PROTOCOL || failed=$(expr $failed + 1)
+ rm -f LOCAL_Z
+done
+
+SHARE="lowercase-30000"
+
+for PROTOCOL in $PROTOCOL_LIST; do
+ test_smbclient "Test lowercase ls 25839 ($PROTOCOL)" $SHARE "ls 25839" -U$USERNAME%$PASSWORD -m$PROTOCOL || failed=$(expr $failed + 1)
+
+ test_smbclient "Test lowercase ls 1 ($PROTOCOL)" $SHARE "ls 1" -U$USERNAME%$PASSWORD -m$PROTOCOL || failed=$(expr $failed + 1)
+ test_smbclient "Test lowercase get 1 ($PROTOCOL)" $SHARE "get 1 LOCAL_1" -U$USERNAME%$PASSWORD -m$PROTOCOL || failed=$(expr $failed + 1)
+ rm -f LOCAL_1
+
+ test_smbclient "Test lowercase ls A ($PROTOCOL)" $SHARE "ls A" -U$USERNAME%$PASSWORD -m$PROTOCOL || failed=$(expr $failed + 1)
+ test_smbclient "Test lowercase get A ($PROTOCOL)" $SHARE "get A LOCAL_A" -U$USERNAME%$PASSWORD -m$PROTOCOL || failed=$(expr $failed + 1)
+ rm -f LOCAL_A
+
+ test_smbclient "Test lowercase ls z ($PROTOCOL)" $SHARE "ls z" -U$USERNAME%$PASSWORD -m$PROTOCOL || failed=$(expr $failed + 1)
+ test_smbclient "Test lowercase get z ($PROTOCOL)" $SHARE "get z LOCAL_Z" -U$USERNAME%$PASSWORD -m$PROTOCOL || failed=$(expr $failed + 1)
+ rm -f LOCAL_Z
+done
+
+exit $failed
diff --git a/source3/script/tests/test_printing_var_exp.sh b/source3/script/tests/test_printing_var_exp.sh
new file mode 100755
index 0000000..5729344
--- /dev/null
+++ b/source3/script/tests/test_printing_var_exp.sh
@@ -0,0 +1,93 @@
+#!/bin/sh
+
+if [ $# -lt 4 ]; then
+ cat <<EOF
+Usage: test_printing_var_exp.sh SERVER SERVER_IP DOMAIN USERNAME PASSWORD
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+SERVER_IP="$2"
+DOMAIN="$3"
+USERNAME="$4"
+PASSWORD="$5"
+shift 5
+ADDARGS="$@"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+. $incdir/common_test_fns.inc
+
+smbclient="$BINDIR/smbclient"
+rpcclient="$BINDIR/rpcclient"
+
+test_var_expansion()
+{
+ logfile="${SELFTEST_TMPDIR}/${USER}_printing_var_exp.log"
+
+ $smbclient -U $DOMAIN/$USERNAME%$PASSWORD \
+ //$SERVER_IP/print_var_exp \
+ -c "print $SRCDIR/testdata/printing/example.ps"
+ if [ $? -ne 0 ]; then
+ rm -f "$logfile"
+ return 1
+ fi
+ cat "$logfile"
+
+ grep "Windows user: $USERNAME" "$logfile"
+ if [ $? -ne 0 ]; then
+ rm -f "$logfile"
+ return 1
+ fi
+ grep "UNIX user: $USERNAME" "$logfile"
+ if [ $? -ne 0 ]; then
+ rm -f "$logfile"
+ return 1
+ fi
+ grep "Domain: $DOMAIN" "$logfile"
+ if [ $? -ne 0 ]; then
+ rm -f "$logfile"
+ return 1
+ fi
+
+ rm -f "$logfile"
+ return 0
+}
+
+test_empty_queue()
+{
+ # Try several times until the bgqd daemon updates the print queue status
+ tries="3"
+ for i in $(seq 1 $tries); do
+ echo "Try $i"
+ JOBS=$($rpcclient ncacn_np:$SERVER_IP \
+ -U $DOMAIN/$USERNAME%$PASSWORD \
+ -c "enumjobs print_var_exp 2")
+ if [ $? -ne 0 ]; then
+ return 1
+ fi
+ if [[ -z $JOBS ]]; then
+ return 0
+ fi
+ if [[ $i -gt $tries ]]; then
+ echo "Print queue not empty after $tries seconds:"
+ echo $JOBS
+ echo "Queue must be empty before leaving this test or" \
+ "following ones may fail."
+ return 1
+ fi
+ sleep 1
+ done
+ return 0
+}
+
+testit "Test variable expansion for '%U', '%u' and '%D'" \
+ test_var_expansion ||
+ failed=$(expr $failed + 1)
+
+testit "Test queue is empty" \
+ test_empty_queue ||
+ failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source3/script/tests/test_pthreadpool.sh b/source3/script/tests/test_pthreadpool.sh
new file mode 100755
index 0000000..b3d24f7
--- /dev/null
+++ b/source3/script/tests/test_pthreadpool.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+if [ ! -x $BINDIR/pthreadpooltest ]; then
+ # Some machines don't have /bin/true, simulate it
+ cat >$BINDIR/pthreadpooltest <<EOF
+#!/bin/sh
+exit 0
+EOF
+ chmod +x $BINDIR/pthreadpooltest
+fi
+
+failed=0
+
+testit "pthreadpool" $VALGRIND $BINDIR/pthreadpooltest ||
+ failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_recycle.sh b/source3/script/tests/test_recycle.sh
new file mode 100755
index 0000000..8c9291f
--- /dev/null
+++ b/source3/script/tests/test_recycle.sh
@@ -0,0 +1,102 @@
+#!/bin/sh
+
+if [ $# -lt 7 ]; then
+ cat <<EOF
+Usage: test_recycle.sh SERVER SERVER_IP USERNAME PASSWORD LOCAL_PATH PREFIX SMBCLIENT ADDARGS
+EOF
+ exit 1
+fi
+
+SERVER="${1}"
+SERVER_IP="${2}"
+USERNAME="${3}"
+PASSWORD="${4}"
+LOCAL_PATH="${5}"
+PREFIX="${6}"
+SMBCLIENT="${7}"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+shift 7
+ADDARGS="$*"
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir"/subunit.sh
+
+failed=0
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+# Define the test environment/filenames.
+#
+share_test_dir="$LOCAL_PATH"
+
+#
+# Cleanup function.
+#
+do_cleanup()
+{
+ (
+ #subshell.
+ cd "$share_test_dir" || return
+ rm -f testfile1
+ rm -f testfile2.tmp
+ rm -rf .trash
+ )
+}
+
+#
+# Ensure we start from a clean slate.
+#
+do_cleanup
+
+
+test_recycle()
+{
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ echo "
+put $tmpfile testfile1
+put $tmpfile testfile2.tmp
+del testfile1
+del testfile2.tmp
+quit
+" > $tmpfile
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/recycle -I$SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+ rm -f "$tmpfile"
+
+ if [ $ret != 0 ]; then
+ printf "%s\n" "$out"
+ printf "failed recycle smbclient run with error %s\n" "$ret"
+ return 1
+ fi
+
+ test -e "$share_test_dir/.trash/testfile1" || {
+ printf ".trash/testfile1 expected to exist but does NOT exist\n"
+ return 1
+ }
+ test -e "$share_test_dir/.trash/testfile2.tmp" && {
+ printf ".trash/testfile2.tmp not expected to exist but DOES exist\n"
+ return 1
+ }
+ perm_want=755
+ perm_is=`stat -c '%a' "$share_test_dir/.trash/"`
+ test "$perm_is" = "$perm_want" || {
+ printf ".trash/ permission should be $perm_want but is $perm_is\n"
+ return 1
+ }
+ return 0
+}
+
+
+testit "recycle" \
+ test_recycle ||
+ failed=$((failed + 1))
+
+#
+# Cleanup.
+do_cleanup
+
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_registry_share.sh b/source3/script/tests/test_registry_share.sh
new file mode 100755
index 0000000..22e9f73
--- /dev/null
+++ b/source3/script/tests/test_registry_share.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+# Blackbox tests for registry shares
+#
+
+if [ $# -lt 3 ]; then
+ cat <<EOF
+Usage: test_registry_share.sh SERVER USERNAME PASSWORD
+EOF
+ exit 1
+fi
+
+SERVER=$1
+USERNAME=$2
+PASSWORD=$3
+shift 3
+failed=0
+
+samba_bindir="$BINDIR"
+samba_srcdir="$SRCDIR"
+smbclient="$samba_bindir/smbclient"
+rpcclient="$samba_bindir/rpcclient"
+
+. $samba_srcdir/testprogs/blackbox/subunit.sh
+. $samba_srcdir/testprogs/blackbox/common_test_fns.inc
+
+test_smbclient \
+ "Test access to registry share [${USERNAME}]" \
+ "ls" "//${SERVER}/registry_share" "-U$USERNAME%$PASSWORD" ||
+ failed=$((failed + 1))
+
+testit_grep_count \
+ "Test for share enum with registry share" \
+ "netname: registry_share" \
+ 1 \
+ ${rpcclient} "ncacn_np:${SERVER}" "-U$USERNAME%$PASSWORD" \
+ -c netshareenum ||
+ failed=$((failed + 1))
+
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_registry_upgrade.sh b/source3/script/tests/test_registry_upgrade.sh
new file mode 100755
index 0000000..ac4a9db
--- /dev/null
+++ b/source3/script/tests/test_registry_upgrade.sh
@@ -0,0 +1,192 @@
+#!/bin/sh
+#
+# Test for registry upgrades.
+#
+# Copyright (C) 2011 Björn Baumbach <bb@sernet.de>
+
+if [ $# -lt 2 ]; then
+ echo "Usage: test_registry_upgrade.sh NET DBWRAP_TOOL"
+ exit 1
+fi
+
+SCRIPT_DIR=$(dirname $0)
+BASE_DIR="${SCRIPT_DIR}/../../.."
+
+NET="$1"
+DBWRAP_TOOL="$2 --persistent"
+DATADIR="${BASE_DIR}/testdata/samba3"
+WORKSPACE="${SELFTEST_TMPDIR}/registry_upgrade"
+CONFIG_FILE="${WORKSPACE}/smb.conf"
+CONFIGURATION="--configfile=${CONFIG_FILE}"
+
+NETCMD="$NET $CONFIGURATION"
+
+incdir="${BASE_DIR}/testprogs/blackbox"
+. $incdir/subunit.sh
+
+failed=0
+
+cd $SELFTEST_TMPDIR || exit 1
+
+REGPATH="HKLM\Software\Samba"
+
+LOGDIR_PREFIX="registry_upgrade"
+
+registry_check()
+(
+ CHECKNO="$1"
+ CHECKDIFF="$2"
+ REGVER=""
+ ALLOWEDERR="INFO: version =|Check database:|overwrite registry format version 0 with 1|no INFO/version found"
+
+ test "x$CHECKNO" = "x0" && {
+ REGVER="--reg-version=1"
+ }
+
+ echo "Registry check $CHECKNO" | tee -a $LOG
+ CHECK="$($NETCMD registry check $REGVER 2>&1)"
+ RC=$?
+
+ ERRORSTR="$(echo "$CHECK" | grep -vE $ALLOWEDERR)"
+ test "x$RC" = "x0" || {
+ echo "upgrade check $CHECKNO failed:" | tee -a $LOG
+ return 1
+ }
+
+ test "x$ERRORSTR" = "x" || {
+ echo "upgrade check $CHECKNO failed:" | tee -a $LOG
+ echo "reason: $CHECK" | tee -a $LOG
+ return 1
+ }
+
+ test "x$CHECKDIFF" = "xcheckdiff" && {
+ $NETCMD registry export 'HKLM' $WORKSPACE/export_${CHECKNO}.reg >>$LOG
+ test "x$?" = "x0" || {
+ echo "Error: 'net registry export HKLM' failed" | tee -a $LOG
+ }
+
+ diff -q $WORKSPACE/export_0.reg $WORKSPACE/export_${CHECKNO}.reg >>$LOG
+ test "x$?" = "x0" || {
+ echo "Error: $WORKSPACE/export_0.reg differs from $WORKSPACE/export_${CHECKNO}.reg" | tee -a $LOG
+ return 1
+ }
+ }
+
+ return 0
+)
+
+registry_upgrade()
+{
+ echo registry_upgrade $1 | tee -a $LOG
+
+ (cat $DATADIR/registry.tdb >$WORKSPACE/registry.tdb) >>$LOG 2>&1
+
+ REGISTRY="${WORKSPACE}/registry.tdb"
+
+ test -e $REGISTRY || {
+ echo "Error: Database file not available" | tee -a $LOG
+ return 1
+ }
+
+ # create config file
+ echo '[global]' >${CONFIG_FILE}
+ echo " state directory = ${WORKSPACE}" >>${CONFIG_FILE}
+ echo " private directory = ${WORKSPACE}" >>${CONFIG_FILE}
+ echo " lock directory = ${WORKSPACE}" >>${CONFIG_FILE}
+
+ # set database INFO/version to 1
+ #$DBWRAP_TOOL $REGISTRY store 'INFO/version' uint32 1
+ #test "x$?" = "x0" || {
+ # echo "Error: Can not set INFO/version" >> $LOG
+ # return 1
+ #}
+
+ # check original registry.tdb
+ echo "$REGISTRY" | tee -a $LOG
+ registry_check 0
+ test "x$?" = "x0" || {
+ echo "Error: initial 'registry_check 0' failed" | tee -a $LOG
+ return 1
+ }
+
+ # trigger upgrade
+ echo "$NETCMD registry enumerate $REGPATH" >>$LOG
+ $NETCMD registry enumerate $REGPATH >>$LOG
+ test "x$?" = "x0" || {
+ echo "Error: 'net registry enumerate $REGPATH' failed" | tee -a $LOG
+ return 1
+ }
+
+ # check upgraded database
+ registry_check 1
+ test "x$?" = "x0" || {
+ echo "Error: 'registry_check 1' after upgrade failed" | tee -a $LOG
+ return 1
+ }
+
+ # export database for diffs
+ $NETCMD registry export 'HKLM' $WORKSPACE/export_0.reg | tee -a $LOG
+ test "x$?" = "x0" || {
+ echo "Error 'net registry export' failed" | tee -a $LOG
+ return 1
+ }
+
+ # remove version string
+ $DBWRAP_TOOL $REGISTRY delete INFO/version | tee -a $LOG
+ test "x$?" = "x0" || {
+ echo "Error: Can not remove INFO/version key from registry" | tee -a $LOG
+ return 1
+ }
+
+ # trigger upgrade on upgraded database
+ echo "$NETCMD registry enumerate $REGPATH" >>$LOG
+ $NETCMD registry enumerate $REGPATH >>$LOG 2>&1
+ test "x$?" = "x0" || {
+ echo "Error: 'net registry enumerate $REGPATH' failed" | tee -a $LOG
+ return 1
+ }
+
+ # check upgraded database again
+ registry_check 2 checkdiff
+ test "x$?" = "x0" || {
+ echo "Error: 'registry_check 2' after upgrade failed" | tee -a $LOG
+ return 1
+ }
+
+ # set database INFO/version to version 2
+ $DBWRAP_TOOL $REGISTRY store 'INFO/version' uint32 2
+ test "x$?" = "x0" || {
+ echo "Error: Can not set INFO/version" | tee -a $LOG
+ return 1
+ }
+
+ # trigger upgrade
+ $NETCMD registry enumerate $REGPATH >>$LOG
+ test "x$?" = "x0" || {
+ echo "Error: 'net registry enumerate $REGPATH' failed" | tee -a $LOG
+ return 1
+ }
+
+ # check upgraded database again
+ registry_check 3 checkdiff
+ test "x$?" = "x0" || {
+ echo "Error: 'registry_check 3' after upgrade failed" | tee -a $LOG
+ return 1
+ }
+}
+
+# remove old workspace
+rm -rf $WORKSPACE
+
+mkdir $WORKSPACE
+
+DIR=$(mktemp -d ${WORKSPACE}/${LOGDIR_PREFIX}_XXXXXX)
+LOG=$DIR/log
+
+testit "registry_upgrade" registry_upgrade || failed=$(expr $failed + 1)
+
+if [ $failed -eq 0 ]; then
+ rm -rf $WORKSPACE
+fi
+
+testok $0 $failed
diff --git a/source3/script/tests/test_resolvconf.sh b/source3/script/tests/test_resolvconf.sh
new file mode 100755
index 0000000..6cf189c
--- /dev/null
+++ b/source3/script/tests/test_resolvconf.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+if [ ! -x $BINDIR/resolvconftest ]; then
+ # Some machines don't have /bin/true, simulate it
+ cat >$BINDIR/resolvconftest <<EOF
+#!/bin/sh
+exit 0
+EOF
+ chmod +x $BINDIR/resolvconftest
+fi
+
+failed=0
+
+testit "resolvconf" $VALGRIND $BINDIR/resolvconftest ||
+ failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_rofs.sh b/source3/script/tests/test_rofs.sh
new file mode 100755
index 0000000..72901e5
--- /dev/null
+++ b/source3/script/tests/test_rofs.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+# Test smbd handling EROFS when creating a file
+# Copyright (C) 2023 Volker Lendecke
+
+if [ $# -ne 4 ]; then
+ echo Usage: $0 SERVERCONFFILE SMBCLIENT SERVER SHARE
+ exit 1
+fi
+
+CONF=$1
+shift 1
+SMBCLIENT=$1
+shift 1
+SERVER=$1
+shift 1
+SHARE=$1
+shift 1
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+error_inject_conf=$(dirname ${SERVERCONFFILE})/error_inject.conf
+echo "error_inject:openat_create = EROFS" >${error_inject_conf}
+
+failed=0
+
+out=$(${SMBCLIENT} //${SERVER}/${SHARE} ${CONF} -U${USER}%${PASSWORD} \
+ -c "put VERSION")
+testit_grep "Expect MEDIA_WRITE_PROTECTED" NT_STATUS_MEDIA_WRITE_PROTECTED \
+ echo "$out" || failed=$(expr $failed + 1)
+
+>${error_inject_conf}
+
+testok $0 $failed
diff --git a/source3/script/tests/test_rpcclient.sh b/source3/script/tests/test_rpcclient.sh
new file mode 100755
index 0000000..4260963
--- /dev/null
+++ b/source3/script/tests/test_rpcclient.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+if [ $# -lt 1 ]; then
+ cat <<EOF
+Usage: test_rpcclient.sh ccache binding <rpcclient commands>
+EOF
+ exit 1
+fi
+
+KRB5CCNAME=$1
+shift 1
+export KRB5CCNAME
+ADDARGS="$*"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+testit "rpcclient" $VALGRIND $BINDIR/rpcclient $ADDARGS || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_rpcclient_dfs.sh b/source3/script/tests/test_rpcclient_dfs.sh
new file mode 100755
index 0000000..0ae9e50
--- /dev/null
+++ b/source3/script/tests/test_rpcclient_dfs.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+#
+# Copyright (c) 2022 Pavel Filipenský <pfilipen@redhat.com>
+#
+# Blackbox tests for the rpcclient DFS commands
+
+if [ $# -lt 4 ]; then
+ cat <<EOF
+Usage: test_rpcclient_dfs.sh USERNAME PASSWORD SERVER RPCCLIENT
+EOF
+ exit 1
+fi
+
+USERNAME="$1"
+PASSWORD="$2"
+SERVER="$3"
+RPCCLIENT="$4"
+
+RPCCLIENTCMD="${VALGRIND} ${RPCCLIENT} ${SERVER} -U${USERNAME}%${PASSWORD}"
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "${incdir}"/subunit.sh
+
+failed=0
+
+${RPCCLIENTCMD} -c "dfsversion"
+RC=$?
+testit "dfsversion" test ${RC} -eq 0 || failed=$((failed + 1))
+
+${RPCCLIENTCMD} -c "dfsenum 5"
+RC=$?
+testit "dfsenum" test ${RC} -eq 0 || failed=$((failed + 1))
+
+# This test fails: _dfs_EnumEx() is not implemented on samba RPC server side
+${RPCCLIENTCMD} -c "dfsenumex 5"
+RC=$?
+testit "dfsenumex" test ${RC} -eq 0 || failed=$((failed + 1))
+
+# Every backslash is reduced twice, so we need to enter it 4 times.
+# Rpc server then gets: '\\server\share\path'
+${RPCCLIENTCMD} -c "dfsgetinfo \\\\\\\\${SERVER}\\\\msdfs-share\\\\msdfs-src1 ${SERVER} msdfs-src1"
+RC=$?
+testit "dfsgetinfo" test ${RC} -eq 0 || failed=$((failed + 1))
+
+testok "$0" "${failed}"
diff --git a/source3/script/tests/test_rpcclient_lookup.sh b/source3/script/tests/test_rpcclient_lookup.sh
new file mode 100755
index 0000000..cc49838
--- /dev/null
+++ b/source3/script/tests/test_rpcclient_lookup.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# Blackbox tests for the rpcclient LSA lookup commands
+#
+# Copyright (C) 2020 Christof Schmitt
+
+if [ $# -lt 4 ]; then
+ cat <<EOF
+Usage: test_rpcclient_lookup.sh USERNAME PASSWORD SERVER RPCCLIENT
+EOF
+ exit 1
+fi
+
+USERNAME="$1"
+PASSWORD="$2"
+SERVER="$3"
+RPCCLIENT="$4"
+
+RPCCLIENTCMD="$RPCCLIENT $SERVER -U$USERNAME%$PASSWORD"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+$RPCCLIENTCMD -c "lookupsids S-1-1-0"
+RC=$?
+testit "lookupsids" test $RC -eq 0 || failed=$(expr $failed + 1)
+
+$RPCCLIENTCMD -c "lookupsids_level 1 S-1-1-0"
+RC=$?
+testit "lookupsids_level" test $RC -eq 0 || failed=$(expr $failed + 1)
+
+$RPCCLIENTCMD -c "lookupnames Everyone"
+RC=$?
+testit "lookupnames" test $RC -eq 0 || failed=$(expr $failed + 1)
+
+$RPCCLIENTCMD -c "lookupnames_level 1 Everyone"
+RC=$?
+testit "lookupnames_level" test $RC -eq 0 || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_rpcclient_netsessenum.sh b/source3/script/tests/test_rpcclient_netsessenum.sh
new file mode 100755
index 0000000..1d04543
--- /dev/null
+++ b/source3/script/tests/test_rpcclient_netsessenum.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+#
+# Blackbox tests for the rpcclient srvsvc commands
+#
+# Copyright (C) 2018 Christof Schmitt
+
+if [ $# -lt 6 ]; then
+ cat <<EOF
+Usage: $0 DOMAIN ADMIN_USER ADMIN_PASSWORD SERVER RPCCLIENT SMBTORTURE3 SHARE
+EOF
+ exit 1
+fi
+
+DOMAIN="$1"
+ADMIN_USER="$2"
+ADMIN_PASSWORD="$3"
+SERVER="$4"
+RPCCLIENT="$5"
+SMBTORTURE3="$6"
+SHARE="$7"
+
+USERPASS="-U$DOMAIN/$ADMIN_USER%$ADMIN_PASSWORD"
+RPCCLIENTCMD="$RPCCLIENT $SERVER $USERPASS"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+#
+# Verify initial number of sessions.
+#
+$RPCCLIENTCMD -c NetSessEnum | grep Received
+RC=$?
+testit "netsessenum" test $RC = 0 || failed=$(expr $failed + 1)
+
+OUT=$($RPCCLIENTCMD -c NetSessEnum | grep Received)
+test "$OUT" = "Received 1 entries."
+RC=$?
+testit "count1" test $RC -eq 0 || failed=$(expr $failed + 1)
+
+#
+# Inject smbd crash
+#
+$SMBTORTURE3 //"$SERVER"/"$SHARE" "$USERPASS" CLEANUP1
+
+#
+# Verify number of sessions after crash
+#
+OUT=$($RPCCLIENTCMD -c NetSessEnum | grep Received)
+test "$OUT" = "Received 1 entries."
+RC=$?
+testit "count2" test $RC -eq 0 || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_rpcclient_pw_nt_hash.sh b/source3/script/tests/test_rpcclient_pw_nt_hash.sh
new file mode 100755
index 0000000..c1e3660
--- /dev/null
+++ b/source3/script/tests/test_rpcclient_pw_nt_hash.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+#
+# Blackbox tests for the rpcclient --pw-nt-hash option
+#
+
+if [ $# -lt 4 ]; then
+ cat <<EOF
+Usage: test_rpcclient_pw_nt_hash.sh USERNAME PASSWORD SERVER RPCCLIENT
+EOF
+ exit 1
+fi
+
+USERNAME="$1"
+PASSWORD="$2"
+SERVER="$3"
+RPCCLIENT="$4"
+
+HASH=$(echo -n $PASSWORD | $PYTHON -c 'import sys, binascii, samba, samba.crypto; sys.stdout.buffer.write(binascii.hexlify(samba.crypto.md4_hash_blob(sys.stdin.buffer.read(1000).decode().encode("UTF-16LE"))))')
+
+RPCCLIENTCMD="$RPCCLIENT $SERVER --pw-nt-hash -U$USERNAME%$HASH -c queryuser"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+testit "rpcclient --pw-nt-hash" $RPCCLIENTCMD || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_rpcclient_samlogon.sh b/source3/script/tests/test_rpcclient_samlogon.sh
new file mode 100755
index 0000000..ff73be5
--- /dev/null
+++ b/source3/script/tests/test_rpcclient_samlogon.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+if [ $# -lt 3 ]; then
+ cat <<EOF
+Usage: test_rpcclient_samlogon.sh USERNAME PASSWORD binding <rpcclient commands>
+EOF
+ exit 1
+fi
+
+USERNAME="$1"
+PASSWORD="$2"
+shift 2
+ADDARGS="$@"
+
+rpcclient_samlogon_schannel_seal()
+{
+ $VALGRIND $BINDIR/rpcclient -U% -c "schannel;samlogon '$USERNAME' '$PASSWORD';samlogon '$USERNAME' '$PASSWORD'" "$@"
+}
+
+rpcclient_samlogon_schannel_sign()
+{
+ $VALGRIND $BINDIR/rpcclient -U% -c "schannelsign;samlogon '$USERNAME' '$PASSWORD';samlogon '$USERNAME' '$PASSWORD'" "$@"
+}
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+testit "rpcclient dsenumdomtrusts" $VALGRIND $BINDIR/rpcclient $ADDARGS -U% -c "dsenumdomtrusts" || failed=$(expr $failed + 1)
+testit "rpcclient getdcsitecoverage" $VALGRIND $BINDIR/rpcclient $ADDARGS -U% -c "getdcsitecoverage" || failed=$(expr $failed + 1)
+testit "rpcclient samlogon schannel seal" rpcclient_samlogon_schannel_seal $ADDARGS || failed=$(expr $failed +1)
+testit "rpcclient samlogon schannel sign" rpcclient_samlogon_schannel_sign $ADDARGS || failed=$(expr $failed +1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_rpcclientsrvsvc.sh b/source3/script/tests/test_rpcclientsrvsvc.sh
new file mode 100755
index 0000000..fdade1a
--- /dev/null
+++ b/source3/script/tests/test_rpcclientsrvsvc.sh
@@ -0,0 +1,90 @@
+#!/bin/sh
+#
+# Blackbox tests for the rpcclient srvsvc commands
+#
+# Copyright (C) 2015 Christof Schmitt
+
+if [ $# -lt 5 ]; then
+ cat <<EOF
+Usage: test_rpcclientsrvsvc.sh USERNAME PASSWORD SERVER RPCCLIENT SHARE1
+EOF
+ exit 1
+fi
+
+USERNAME="$1"
+PASSWORD="$2"
+SERVER="$3"
+RPCCLIENT="$4"
+SHARE1="$5"
+
+RPCCLIENTCMD="$RPCCLIENT $SERVER -U$USERNAME%$PASSWORD"
+
+SHARENAME=SRVSVCTEST
+MAX_USERS=5
+COMMENT="share for RPC SRVSVC testing"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+# Query path from existing share
+
+$RPCCLIENTCMD -c "netsharegetinfo $SHARE1"
+RC=$?
+testit "getinfo on S$SHARE1" test $RC = 0 || failed=$(expr $failed + 1)
+
+SHAREPATH=$($RPCCLIENTCMD -c "netsharegetinfo '$SHARE1'" |
+ grep path: | sed -e 's/.*path:\t//')
+testit "verifying $SHARE1 path" test -n "$SHAREPATH" ||
+ failed=$(expr $failed + 1)
+
+# Add a new share
+
+$RPCCLIENTCMD -c "netshareadd '$SHAREPATH' '$SHARENAME' '$MAX_USERS' '$COMMENT'"
+RC=$?
+testit "netshareadd" test $RC = 0 || failed=$(expr $failed + 1)
+
+# Verify comment for new share
+
+COMMENT_RET=$($RPCCLIENTCMD -c "netsharegetinfo '$SHARENAME'" |
+ grep remark: | sed -e 's/.*remark:\t//')
+
+test "$COMMENT" = "$COMMENT_RET"
+RC=$?
+testit "verifying comment" test $RC -eq 0 || failed=$(expr $failed + 1)
+
+# Verify share path for new share
+
+SHAREPATH_RET=$($RPCCLIENTCMD -c "netsharegetinfo '$SHARENAME'" |
+ grep path: | sed -e 's/.*path:\t//')
+test "$SHAREPATH" = "$SHAREPATH_RET"
+RC=$?
+testit "verifying share path" test $RC -eq 0 || failed=$(expr $failed + 1)
+
+# Set CSC policy
+
+$RPCCLIENTCMD -c "netsharesetdfsflags '$SHARENAME' 0x30"
+RC=$?
+testit "set csc policy" test $RC -eq 0 || failed=$(expr $failed + 1)
+
+# Query CSC policy
+
+CSC_CACHING_RET=$($RPCCLIENTCMD -c "netsharegetinfo '$SHARENAME' 1005" |
+ grep 'csc caching' | sed -e 's/.*csc caching: //')
+testit "verifying csc policy" test $CSC_CACHING_RET -eq 3 ||
+ failed=$(expr $failed + 1)
+
+# Delete share
+
+$RPCCLIENTCMD -c "netsharedel '$SHARENAME'"
+RC=$?
+testit "deleting share" test $RC -eq 0 || failed=$(expr $failed + 1)
+
+# Verify that query to deleted share fails
+
+$RPCCLIENTCMD -c "netsharegetinfo '$SHARENAME' 1005"
+RC=$?
+testit "querying deleted share" test $RC -eq 1 || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_sacl_set_get.sh b/source3/script/tests/test_sacl_set_get.sh
new file mode 100755
index 0000000..1c78ab2
--- /dev/null
+++ b/source3/script/tests/test_sacl_set_get.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+#
+# Runs the smbtorture3 SMB2-SACL test
+# that requires SeSecurityPrivilege
+# against Samba.
+#
+
+if [ $# -lt 7 ]; then
+ echo "Usage: $0 SERVER SERVER_IP USERNAME PASSWORD SMBTORTURE3 NET SHARE"
+ exit 1
+fi
+
+SERVER="$1"
+SERVER_IP="$2"
+USERNAME="$3"
+PASSWORD="$4"
+SMBTORTURE3="$5"
+NET="$6"
+SHARE="$7"
+
+failed=0
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+sacl_set_get()
+{
+ out=$($SMBTORTURE3 //$SERVER_IP/$SHARE -U $USERNAME%$PASSWORD SMB2-SACL)
+ if [ $? -ne 0 ]; then
+ echo "SMB2-SACL failed"
+ echo "$out"
+ return 1
+ fi
+}
+
+# Grant SeSecurityPrivilege to the user
+testit "grant SeSecurityPrivilege" $NET rpc rights grant $USERNAME SeSecurityPrivilege -U $USERNAME%$PASSWORD -I $SERVER_IP || failed=$(expr $failed + 1)
+
+# Run the tests.
+testit "SACL set_get" sacl_set_get || failed=$(expr $failed + 1)
+
+# Revoke SeSecurityPrivilege
+testit "revoke SeSecurityPrivilege" $NET rpc rights revoke $USERNAME SeSecurityPrivilege -U $USERNAME%$PASSWORD -I $SERVER_IP || failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source3/script/tests/test_server_addresses.sh b/source3/script/tests/test_server_addresses.sh
new file mode 100755
index 0000000..891c2f2
--- /dev/null
+++ b/source3/script/tests/test_server_addresses.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# Blackbox test for the server addresses parameter
+#
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+testit_grep_count \
+ "[only_ipv6] invisible over ipv4" "netname: only_ipv6" 0 \
+ bin/rpcclient "$SERVER_IP" -U% -c netshareenumall ||
+ failed=$(expr "$failed" + 1)
+
+testit_grep_count \
+ "[only_ipv6] visible over ipv6" "netname: only_ipv6" 1 \
+ bin/rpcclient "$SERVER_IPV6" -U% -c netshareenumall ||
+ failed=$(expr "$failed" + 1)
+
+testit_expect_failure_grep \
+ "[only_ipv6] inaccessible over ipv4" \
+ "tree connect failed: NT_STATUS_BAD_NETWORK_NAME" \
+ bin/smbclient //"$SERVER_IP"/only_ipv6 -U% -c quit ||
+ failed=$(expr "$failed" + 1)
+
+testit \
+ "[only_ipv6] accessible over ipv6" \
+ bin/smbclient //"$SERVER_IPV6"/only_ipv6 -U% -c quit ||
+ failed=$(expr "$failed" + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_shadow_copy.sh b/source3/script/tests/test_shadow_copy.sh
new file mode 100755
index 0000000..dd6699f
--- /dev/null
+++ b/source3/script/tests/test_shadow_copy.sh
@@ -0,0 +1,458 @@
+#!/usr/bin/env bash
+#
+# Blackbox test for shadow_copy2 VFS.
+#
+
+if [ $# -lt 7 ]; then
+cat <<EOF
+Usage: test_shadow_copy SERVER SERVER_IP DOMAIN USERNAME PASSWORD WORKDIR SMBCLIENT PARAMS
+EOF
+exit 1;
+fi
+
+SERVER=${1}
+SERVER_IP=${2}
+DOMAIN=${3}
+USERNAME=${4}
+PASSWORD=${5}
+WORKDIR=${6}
+SMBCLIENT=${7}
+shift 7
+ADDARGS="$*"
+SMBCLIENT="$VALGRIND ${SMBCLIENT} ${ADDARGS}"
+
+incdir=`dirname $0`/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+SNAPSHOTS[0]='@GMT-2015.10.31-19.40.30'
+SNAPSHOTS[1]='@GMT-2016.10.31-19.40.30'
+SNAPSHOTS[2]='@GMT-2017.10.31-19.40.30'
+SNAPSHOTS[3]='@GMT-2018.10.31-19.40.30'
+SNAPSHOTS[4]='@GMT-2019.10.31-19.40.30'
+SNAPSHOTS[5]='@GMT-2020.10.31-19.40.30'
+SNAPSHOTS[6]='@GMT-2021.10.31-19.40.30'
+SNAPSHOTS[7]='@GMT-2022.10.31-19.40.30'
+SNAPSHOTS[8]='@GMT-2023.10.31-19.40.30'
+SNAPSHOTS[9]='@GMT-2024.10.31-19.40.30'
+SNAPSHOTS[10]='@GMT-2010-11-11'
+SNAPSHOTS[11]='@GMT-2011.11.11-11.40.30'
+SNAPSHOTS[12]='snap@GMT-2012.11.11-11.40.30'
+SNAPSHOTS[13]='@GMT-2013.11.11-11_40_33-snap'
+SNAPSHOTS[14]='@GMT-2014.11.11-11.40.30'
+SNAPSHOTS[15]='daily@GMT-2015.11.11-11.40.30'
+SNAPSHOTS[16]='snap_GMT-2016.11.11-11.40.30'
+SNAPSHOTS[17]='sysp_GMT-2017.11.11-11.40.30'
+SNAPSHOTS[18]='monthly@GMT-2018.11.11-11.40.30'
+SNAPSHOTS[19]='straps_GMT-2019.11.11-11.40.33'
+
+# build a hierarchy of files, symlinks, and directories
+build_files()
+{
+ local rootdir
+ local prefix
+ local version
+ local destdir
+ local content
+ rootdir=$1
+ prefix=$2
+ version=$3
+ content=$4
+ if [ -n "$prefix" ] ; then
+ destdir=$rootdir/$prefix
+ else
+ destdir=$rootdir
+ fi
+
+ mkdir -p $destdir
+ if [ "$version" = "latest" ] ; then
+ #non-snapshot files
+ # for non-snapshot version, create legit files
+ # so that wide-link checks focus on snapshot files
+ echo "$content" > $destdir/foo
+ mkdir -p $destdir/bar
+ echo "$content" > $destdir/bar/baz
+ echo "$content" > $destdir/bar/lfoo
+ echo "$content" > $destdir/bar/letcpasswd
+ echo "$content" > $destdir/bar/loutside
+ elif [ "$version" = "fullsnap" ] ; then
+ #snapshot files
+ echo "$content" > $destdir/foo
+ mkdir -p $destdir/bar
+ echo "$content" > $destdir/bar/baz
+ ln -fs ../foo $destdir/bar/lfoo
+ ln -fs /etc/passwd $destdir/bar/letcpasswd
+ ln -fs ../../outside $destdir/bar/loutside
+ echo "$content" > `dirname $destdir`/outside
+ else #subshare snapshot - at bar
+ echo "$content" > $destdir/baz
+ ln -fs ../foo $destdir/lfoo
+ ln -fs /etc/passwd $destdir/letcpasswd
+ ln -fs ../../outside $destdir/loutside
+ echo "$content" > `dirname $destdir`/../outside
+ fi
+
+}
+
+# build a snapshots directory
+build_snapshots()
+{
+ local where #where to build snapshots
+ local prefix #prefix from snapshot dir to share root
+ local start #timestamp index of first snapshot
+ local end #timestamp index of last snapshot
+ local sub #creat a snapshot of subtree of share
+ local snapdir
+ local snapname
+ local i
+ local version
+
+ where=$1
+ prefix=$2
+ start=$3
+ end=$4
+ sub=$5
+
+ snapdir=$where/.snapshots
+ mkdir -p $snapdir
+
+ version="fullsnap"
+ if [ "$sub" = "1" ] ; then
+ version="subsnap"
+ prefix=""
+
+ # a valid link target for an inner symlink -
+ # the link is not broken yet should be blocked
+ # by wide link checks
+ touch $snapdir/foo
+ fi
+
+ for i in `seq $start $end` ; do
+ snapname=${SNAPSHOTS[$i]}
+ mkdir $snapdir/$snapname
+ build_files $snapdir/$snapname "$prefix" $version "$snapname"
+ done
+}
+
+# Test listing previous versions of a file
+test_count_versions()
+{
+ local share
+ local path
+ local expected_count
+ local skip_content
+ local versions
+ local tstamps
+ local tstamp
+ local content
+ local is_dir
+
+ share=$1
+ path=$2
+ expected_count=$3
+ skip_content=$4
+ versions=`$SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "allinfo $path" | grep "^create_time:" | wc -l`
+ if [ "$versions" != "$expected_count" ] ; then
+ echo "expected $expected_count versions of $path, got $versions"
+ return 1
+ fi
+
+ is_dir=0
+ $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "allinfo $path" | grep "^attributes:.*D" && is_dir=1
+ if [ $is_dir = 1 ] ; then
+ skip_content=1
+ fi
+
+ #readable snapshots
+ tstamps=`$SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "allinfo $path" | awk '/^@GMT-/ {snapshot=$1} /^create_time:/ {printf "%s\n", snapshot}'`
+ for tstamp in $tstamps ; do
+ if [ $is_dir = 0 ] ;
+ then
+ if ! $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "get $tstamp\\$path $WORKDIR/foo" ; then
+ echo "Failed getting \\\\$SERVER\\$share\\$tstamp\\$path"
+ return 1
+ fi
+ else
+ if ! $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "ls $tstamp\\$path\\*" ; then
+ echo "Failed listing \\\\$SERVER\\$share\\$tstamp\\$path"
+ return 1
+ fi
+ fi
+
+ #also check the content, but not for wide links
+ if [ "x$skip_content" != "x1" ] ; then
+ content=`cat $WORKDIR/foo`
+ if [ "$content" != "$tstamp" ] ; then
+ echo "incorrect content of \\\\$SERVER\\$share\\$tstamp\\$path expected [$tstamp] got [$content]"
+ return 1
+ fi
+ fi
+ done
+
+ #non-readable snapshots
+ tstamps=`$SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "allinfo $path" | \
+ awk '/^@GMT-/ {if (snapshot!=""){printf "%s\n", snapshot} ; snapshot=$1} /^create_time:/ {snapshot=""} END {if (snapshot!=""){printf "%s\n", snapshot}}'`
+ for tstamp in $tstamps ; do
+ if [ $is_dir = 0 ] ;
+ then
+ if $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "get $tstamp\\$path $WORKDIR/foo" ; then
+ echo "Unexpected success getting \\\\$SERVER\\$share\\$tstamp\\$path"
+ return 1
+ fi
+ else
+ if $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "ls $tstamp\\$path\\*" ; then
+ echo "Unexpected success listing \\\\$SERVER\\$share\\$tstamp\\$path"
+ return 1
+ fi
+ fi
+ done
+}
+
+# Test fetching a previous version of a file
+test_fetch_snap_file()
+{
+ local share
+ local path
+ local snapidx
+
+ share=$1
+ path=$2
+ snapidx=$3
+ $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP \
+ -c "get ${SNAPSHOTS[$snapidx]}/$path $WORKDIR/foo"
+}
+
+# Test fetching a previous version of a file
+test_fetch_snap_dir()
+{
+ local share
+ local path
+ local snapidx
+
+ share=$1
+ path=$2
+ snapidx=$3
+
+ # This first command is not strictly needed, but it causes the snapshots to
+ # appear in a network trace which helps debugging...
+ $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP \
+ -c "allinfo $path"
+
+ $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP \
+ -c "ls ${SNAPSHOTS[$snapidx]}/$path/*"
+}
+
+test_shadow_copy_fixed()
+{
+ local share #share to contact
+ local where #where to place snapshots
+ local prefix #prefix to files inside snapshot
+ local msg
+ local allow_wl
+ local ncopies_allowd
+ local ncopies_blocked
+
+ share=$1
+ where=$2
+ prefix=$3
+ msg=$4
+ allow_wl=$5
+
+ ncopies_allowed=4
+ ncopies_blocked=1
+ if [ -n "$allow_wl" ] ; then
+ ncopies_blocked=4
+ fi
+
+ #delete snapshots from previous tests
+ find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
+ build_snapshots $WORKDIR/$where "$prefix" 0 2
+
+ testit "$msg - regular file" \
+ test_count_versions $share foo $ncopies_allowed || \
+ failed=`expr $failed + 1`
+
+ testit "$msg - regular file in subdir" \
+ test_count_versions $share bar/baz $ncopies_allowed || \
+ failed=`expr $failed + 1`
+
+ testit "$msg - regular file in case insensitive subdir" \
+ test_count_versions $share bar/bAz $ncopies_allowed || \
+ failed=`expr $failed + 1`
+
+ testit "$msg - local symlink" \
+ test_count_versions $share bar/lfoo $ncopies_allowed || \
+ failed=`expr $failed + 1`
+
+ testit "$msg - abs symlink outside" \
+ test_count_versions $share bar/letcpasswd $ncopies_blocked 1 || \
+ failed=`expr $failed + 1`
+
+ testit "$msg - rel symlink outside" \
+ test_count_versions $share bar/loutside $ncopies_blocked 1 || \
+ failed=`expr $failed + 1`
+
+ testit "$msg - list directory" \
+ test_count_versions $share bar $ncopies_allowed || \
+ failed=`expr $failed + 1`
+}
+
+test_shadow_copy_everywhere()
+{
+ local share #share to contact
+
+ share=$1
+
+ #delete snapshots from previous tests
+ find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
+ build_snapshots "$WORKDIR/mount" "base/share" 0 0
+ build_snapshots "$WORKDIR/mount/base" "share" 1 2
+ build_snapshots "$WORKDIR/mount/base/share" "" 3 5
+ build_snapshots "$WORKDIR/mount/base/share/bar" "" 6 9 1
+
+ testit "snapshots in each dir - regular file" \
+ test_count_versions $share foo 4 || \
+ failed=`expr $failed + 1`
+
+ testit "snapshots in each dir - regular file in subdir" \
+ test_count_versions $share bar/baz 5 || \
+ failed=`expr $failed + 1`
+
+ testit "snapshots in each dir - local symlink (but outside snapshot)" \
+ test_count_versions $share bar/lfoo 1 || \
+ failed=`expr $failed + 1`
+
+ testit "snapshots in each dir - abs symlink outside" \
+ test_count_versions $share bar/letcpasswd 1 || \
+ failed=`expr $failed + 1`
+
+ testit "snapshots in each dir - rel symlink outside" \
+ test_count_versions $share bar/loutside 1 || \
+ failed=`expr $failed + 1`
+
+ #the previous versions of the file bar/lfoo points to are outside its
+ #snapshot, and are not reachable. However, but previous versions
+ #taken at different, non-overlapping times higher up the
+ #hierarchy are still reachable.
+ testit "fetch a previous version of a regular file" \
+ test_fetch_snap_file $share "bar/baz" 6 || \
+ failed=`expr $failed + 1`
+
+ testit "fetch a previous version of a regular file via non-canonical parent path" \
+ test_fetch_snap_file $share "BAR/baz" 6 || \
+ failed=`expr $failed + 1`
+
+ testit "fetch a previous version of a regular file via non-canonical basepath" \
+ test_fetch_snap_file $share "bar/BAZ" 6 || \
+ failed=`expr $failed + 1`
+
+ testit "fetch a previous version of a regular file via non-canonical path" \
+ test_fetch_snap_file $share "BAR/BAZ" 6 || \
+ failed=`expr $failed + 1`
+
+ testit_expect_failure "fetch a (non-existent) previous version of a symlink" \
+ test_fetch_snap_file $share "bar/lfoo" 6 || \
+ failed=`expr $failed + 1`
+
+ testit "fetch a previous version of a symlink via browsing (1)" \
+ test_fetch_snap_file $share "bar/lfoo" 0 || \
+ failed=`expr $failed + 1`
+
+ testit "fetch a previous version of a symlink via browsing (2)" \
+ test_fetch_snap_file $share "bar/lfoo" 1 || \
+ failed=`expr $failed + 1`
+
+ testit "fetch a previous version of a symlink via browsing (3)" \
+ test_fetch_snap_file $share "bar/lfoo" 3 || \
+ failed=`expr $failed + 1`
+
+ testit "list a previous version directory" \
+ test_fetch_snap_dir $share "bar" 6 || \
+ failed=`expr $failed + 1`
+}
+
+test_shadow_copy_format()
+{
+ local share #share to contact
+ local where #where to place snapshots
+ local prefix #prefix to files inside snapshot
+ local ncopies_allowd
+ local msg
+
+ share=$1
+ where=$2
+ prefix=$3
+ ncopies_allowed=$4
+ msg=$5
+
+ #delete snapshots from previous tests
+ find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
+ build_snapshots $WORKDIR/$where "$prefix" 10 19
+
+ testit "$msg - regular file" \
+ test_count_versions $share foo $ncopies_allowed 1 || \
+ failed=`expr $failed + 1`
+}
+
+# Test fetching a file where there's no current version of it
+test_missing_basedir()
+{
+ local share
+ local where
+ local prefix
+ local snapidx
+
+ share=$1
+ where=$2
+ prefix=$3
+ snapidx=$4
+
+ #delete snapshots from previous tests
+ find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
+ build_snapshots $WORKDIR/$where "$prefix" "$snapidx" "$snapidx"
+
+ (cd "$WORKDIR/$where"/share; mv bar _bar)
+
+ testit "fetch a file without a latest version" \
+ test_fetch_snap_file "$share" "bar/baz" "$snapidx" || \
+ failed=`expr $failed + 1`
+
+ (cd "$WORKDIR/$where"/share; mv _bar bar)
+}
+
+#build "latest" files
+build_files $WORKDIR/mount base/share "latest" "latest"
+
+failed=0
+
+# a test with wide links allowed - also to verify that what's later
+# being blocked is a result of server security measures and not
+# a testing artifact.
+test_shadow_copy_fixed shadow_wl mount base/share "shadow copies with wide links allowed" 1
+
+# tests for a fixed snapshot location
+test_shadow_copy_fixed shadow1 mount base/share "full volume snapshots mounted under volume"
+test_shadow_copy_fixed shadow2 . base/share "full volume snapshots mounted outside volume"
+test_shadow_copy_fixed shadow3 mount/base share "sub volume snapshots mounted under snapshot point"
+test_shadow_copy_fixed shadow4 . share "sub volume snapshots mounted outside"
+test_shadow_copy_fixed shadow5 mount/base/share "" "full volume snapshots and share mounted under volume"
+test_shadow_copy_fixed shadow6 . "" "full volume snapshots and share mounted outside"
+test_shadow_copy_fixed shadow8 . share "logical snapshot layout"
+
+# tests for snapshot everywhere - one snapshot location
+test_shadow_copy_fixed shadow7 mount base/share "'everywhere' full volume snapshots"
+test_shadow_copy_fixed shadow7 mount/base share "'everywhere' sub volume snapshots"
+test_shadow_copy_fixed shadow7 mount/base/share "" "'everywhere' share snapshots"
+
+# a test for snapshots everywhere - multiple snapshot locations
+test_shadow_copy_everywhere shadow7
+
+# tests for testing snapshot selection via shadow:format
+test_shadow_copy_format shadow_fmt0 mount/base share 3 "basic shadow:format test"
+test_shadow_copy_format shadow_fmt1 mount/base share 2 "shadow:format with only date"
+test_shadow_copy_format shadow_fmt2 mount/base share 2 "shadow:format with some prefix"
+test_shadow_copy_format shadow_fmt3 mount/base share 2 "shadow:format with modified format"
+test_shadow_copy_format shadow_fmt4 mount/base share 3 "shadow:format with snapprefix"
+test_shadow_copy_format shadow_fmt5 mount/base share 6 "shadow:format with delimiter"
+test_missing_basedir shadow3 "mount/base" "share" 6
+
+exit $failed
diff --git a/source3/script/tests/test_shadow_copy_torture.sh b/source3/script/tests/test_shadow_copy_torture.sh
new file mode 100755
index 0000000..3a6ba91
--- /dev/null
+++ b/source3/script/tests/test_shadow_copy_torture.sh
@@ -0,0 +1,227 @@
+#!/usr/bin/env bash
+#
+# Blackbox test for shadow_copy2 VFS.
+#
+
+if [ $# -lt 7 ]; then
+ cat <<EOF
+Usage: test_shadow_copy SERVER SERVER_IP DOMAIN USERNAME PASSWORD WORKDIR SMBTORTURE SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER=${1}
+SERVER_IP=${2}
+DOMAIN=${3}
+USERNAME=${4}
+PASSWORD=${5}
+WORKDIR=${6}
+SMBTORTURE="$VALGRIND ${7}"
+SMBCLIENT="$VALGRIND ${8}"
+shift 7
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+SNAPSHOT="@GMT-2015.10.31-19.40.30"
+
+failed=0
+
+cd $SELFTEST_TMPDIR || exit 1
+
+# build a hierarchy of files, symlinks, and directories
+build_files()
+{
+ local destdir
+ destdir=$1
+
+ echo "$content" >$destdir/foo
+
+ mkdir -p $WORKDIR/subdir/
+ touch $WORKDIR/subdir/hardlink
+}
+
+# build a snapshots directory
+build_snapshots()
+{
+ local snapdir
+
+ snapdir=$WORKDIR/.snapshots
+
+ mkdir -p $snapdir/$SNAPSHOT
+
+ build_files $snapdir/$SNAPSHOT
+
+ mkdir -p $snapdir/$SNAPSHOT/subdir
+ ln "$WORKDIR"/subdir/hardlink "$snapdir"/$SNAPSHOT/subdir/hardlink
+}
+
+build_stream_on_snapshot()
+{
+ file=$WORKDIR/.snapshots/$SNAPSHOT/foo
+
+ setfattr -n 'user.DosStream.bar:$DATA' -v baz $file || return 1
+}
+
+test_shadow_copy_write()
+{
+ local msg
+
+ msg=$1
+
+ #delete snapshots from previous tests
+ find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
+ build_snapshots
+
+ testit "writing to shadow copy of a file" \
+ $SMBTORTURE \
+ -U$USERNAME%$PASSWORD \
+ "//$SERVER/shadow_write" \
+ --option="torture:twrp_file=foo" \
+ --option="torture:twrp_snapshot=$SNAPSHOT" \
+ smb2.twrp.write ||
+ failed=$(expr $failed + 1)
+}
+
+test_shadow_copy_stream()
+{
+ local msg
+
+ msg=$1
+
+ #delete snapshots from previous tests
+ find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
+ build_snapshots
+ build_stream_on_snapshot || {
+ subunit_start_test msg
+ subunit_skip_test msg <<EOF
+test_shadow_copy_stream needs an fs with xattrs
+EOF
+ return 0
+ }
+
+ testit "reading stream of a shadow copy of a file" \
+ $SMBTORTURE \
+ -U$USERNAME%$PASSWORD \
+ "//$SERVER/shadow_write" \
+ --option="torture:twrp_file=foo" \
+ --option="torture:twrp_stream=bar" \
+ --option="torture:twrp_stream_size=3" \
+ --option="torture:twrp_snapshot=$SNAPSHOT" \
+ smb2.twrp.stream ||
+ failed=$(expr $failed + 1)
+}
+
+test_shadow_copy_openroot()
+{
+ local msg
+
+ msg=$1
+
+ #delete snapshots from previous tests
+ find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
+ build_snapshots
+
+ testit "opening shadow copy root of share" \
+ $SMBTORTURE \
+ -U$USERNAME%$PASSWORD \
+ "//$SERVER/shadow_write" \
+ --option="torture:twrp_snapshot=$SNAPSHOT" \
+ smb2.twrp.openroot ||
+ failed=$(expr $failed + 1)
+}
+
+test_shadow_copy_fix_inodes()
+{
+ local msg
+
+ msg=$1
+
+ #delete snapshots from previous tests
+ find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
+ build_snapshots
+
+ out=$($SMBCLIENT \
+ -U $USERNAME%$PASSWORD \
+ "//$SERVER/shadow_write" \
+ -c "open $SNAPSHOT/subdir/hardlink") || failed=$(expr $failed + 1)
+ echo $out
+ echo $out | grep "hardlink: for read/write fnum 1" || return 1
+}
+
+build_hiddenfile()
+{
+ local snapdir
+
+ snapdir=$WORKDIR/.snapshots
+
+ #delete snapshots from previous tests
+ find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
+ build_snapshots
+
+ touch $WORKDIR/hiddenfile
+
+ # Create a file with hidden attribute
+ $SMBCLIENT -U $USERNAME%$PASSWORD \
+ "//$SERVER/shadow_write" \
+ -c "put $WORKDIR/hiddenfile hiddenfile; setmode hiddenfile +h"
+ # ...and move it to the snapshot directory
+ mv $WORKDIR/hiddenfile $snapdir/$SNAPSHOT/
+}
+
+test_hiddenfile()
+{
+ build_hiddenfile
+
+ out=$($SMBCLIENT \
+ -U $USERNAME%$PASSWORD \
+ "//$SERVER/shadow_write" \
+ -c "allinfo $SNAPSHOT/hiddenfile") || return 1
+ echo $out
+ echo $out | grep "attributes: HA (22)" || return 1
+
+ out=$($SMBCLIENT \
+ -U $USERNAME%$PASSWORD \
+ "//$SERVER/shadow_write" \
+ -c "ls $SNAPSHOT/hiddenfile") || return 1
+ echo $out
+ echo $out | grep "hiddenfile[[:blank:]]*AH" || return 1
+
+ return 0
+}
+
+test_shadow_copy_listdir_fix_inodes()
+{
+ local msg
+
+ msg=$1
+
+ #delete snapshots from previous tests
+ find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
+ build_snapshots
+
+ testit "$msg" \
+ $SMBTORTURE \
+ -U$USERNAME%$PASSWORD \
+ "//$SERVER/shadow_write" \
+ --option="torture:twrp_snapshot=$SNAPSHOT" \
+ smb2.twrp.listdir ||
+ failed=$(expr $failed + 1)
+}
+
+build_files $WORKDIR
+
+# test open for writing and write behaviour of snapshoted files
+test_shadow_copy_write "write behaviour of snapshoted files"
+
+test_shadow_copy_stream "reading stream of snapshotted file"
+
+test_shadow_copy_openroot "opening root of shadow copy share"
+
+testit "fix inodes with hardlink" test_shadow_copy_fix_inodes || failed=$(expr $failed + 1)
+
+testit "Test reading DOS attribute" test_hiddenfile || failed=$(expr $failed + 1)
+
+test_shadow_copy_listdir_fix_inodes "fix inodes when listing directory"
+
+exit $failed
diff --git a/source3/script/tests/test_shareenum.sh b/source3/script/tests/test_shareenum.sh
new file mode 100755
index 0000000..0334243
--- /dev/null
+++ b/source3/script/tests/test_shareenum.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+# this tests share enumeration with "access based share enum"
+
+if [ $# -lt 4 ]; then
+ cat <<EOF
+Usage: $0 SERVER USERNAME PASSWORD RPCCLIENT
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+USERNAME="$2"
+PASSWORD="$3"
+RPCCLIENT="$4"
+RPCCLIENT="$VALGRIND ${RPCCLIENT}"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+user_see_share()
+{
+ local user=$1
+ local share=$2
+ $RPCCLIENT //$SERVER -U$user%$PASSWORD -c "netshareenumall" | grep $share >/dev/null 2>&1
+}
+
+testit "$USERNAME sees tmp" user_see_share $USERNAME tmp
+testit "$USERNAME sees valid-users-tmp" user_see_share $USERNAME valid-users-tmp
+testit "force_user sees tmp" user_see_share force_user tmp
+testit_expect_failure "force_user does not see valid-users-tmp" user_see_share force_user valid-users-tmp
diff --git a/source3/script/tests/test_sharesec.sh b/source3/script/tests/test_sharesec.sh
new file mode 100755
index 0000000..a083a56
--- /dev/null
+++ b/source3/script/tests/test_sharesec.sh
@@ -0,0 +1,140 @@
+#!/bin/sh
+#
+# Test sharesec command.
+#
+# Verify that changing and querying the security descriptor works. Also
+# ensure that the output format for ACL entries does not change.
+#
+# The test uses well-known SIDs to not require looking up names and SIDs
+#
+# Copyright (C) 2015, 2019 Christof Schmitt
+
+if [ $# -lt 4 ]; then
+ echo Usage: test_sharesec.sh SERVERCONFFILE SHARESEC NET SHARE
+ exit 1
+fi
+
+CONF=$1
+SHARESEC=$2
+NET=$3
+SHARE=$4
+
+CMD="$SHARESEC $CONF $SHARE"
+NET_CMD="$NET $CONF"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+testit "Set new ACL" $CMD --replace S-1-1-0:ALLOWED/0x0/READ ||
+ failed=$(expr $failed + 1)
+testit "Query new ACL" $CMD --view || failed=$(expr $failed + 1)
+COUNT=$($CMD --view | grep ACL: | sed -e 's/^ACL://' | wc -l)
+testit "Verify new ACL count" test $COUNT -eq 1 || failed=$(expr $failed + 1)
+ACL=$($CMD --view | grep ACL: | sed -e 's/^ACL://')
+testit "Verify new ACL" test $ACL = S-1-1-0:ALLOWED/0x0/READ
+
+OWNER=$($CMD --view | grep OWNER:)
+testit "Verify empty OWNER" test "$OWNER" = "OWNER:" ||
+ failed=$(expr $failed + 1)
+GROUP=$($CMD --view | grep GROUP:)
+testit "Verify empty GROUP" test "$GROUP" = "GROUP:" ||
+ failed=$(expr $failed + 1)
+CONTROL=$($CMD --view | grep CONTROL: | sed -e 's/^CONTROL://')
+testit "Verify control flags" test "$CONTROL" = "SR|DP" ||
+ failed=$(expr $failed + 1)
+
+testit "Add second ACL entry" $CMD --add S-1-5-32-544:ALLOWED/0x0/FULL ||
+ failed=$(expr $failed + 1)
+testit "Query ACL with two entries" $CMD --view ||
+ failed=$(expr $failed + 1)
+COUNT=$($CMD --view | grep ACL: | sed -e 's/^ACL://' | wc -l)
+testit "Verify ACL count with two entries" test $COUNT -eq 2 ||
+ failed=$(expr $failed + 1)
+ACL=$($CMD --view | grep S-1-5-32-544 | sed -e 's/^ACL://')
+testit "Verify second ACL entry" test $ACL = S-1-5-32-544:ALLOWED/0x0/FULL ||
+ failed=$(expr $failed + 1)
+
+testit "Modify ACL entry" $CMD --modify S-1-5-32-544:ALLOWED/0x0/CHANGE ||
+ failed=$(expr $failed + 1)
+testit "Verify ACL with two entries after modify" $CMD --view ||
+ failed=$(expr $failed + 1)
+COUNT=$($CMD --view | grep ACL: | sed -e 's/^ACL://' | wc -l)
+testit "Verify ACL count with two entries after modify" test $COUNT -eq 2 ||
+ failed=$(expr $failed + 1)
+ACL=$($CMD --view | grep S-1-5-32-544 | sed -e 's/^ACL://')
+testit "Verify modified entry" test $ACL = S-1-5-32-544:ALLOWED/0x0/CHANGE ||
+ failed=$(expr $failed + 1)
+
+testit "Add deny ACL entry" $CMD --add S-1-5-32-545:DENIED/0x0/CHANGE ||
+ failed=$(expr $failed + 1)
+testit "Query ACL with three entries" $CMD --view ||
+ failed=$(expr $failed + 1)
+COUNT=$($CMD --view | grep ACL: | sed -e 's/^ACL://' | wc -l)
+testit "Verify ACL count with three entries" test $COUNT -eq 3 ||
+ failed=$(expr $failed + 1)
+ACL=$($CMD --view | grep S-1-5-32-545 | sed -e 's/^ACL://')
+testit "Verify DENIED ACL entry" test $ACL = S-1-5-32-545:DENIED/0x0/CHANGE ||
+ failed=$(expr $failed + 1)
+
+testit "Add special ACL entry" $CMD --add S-1-5-32-546:ALLOWED/0x0/RWXDP ||
+ failed=$(expr $failed + 1)
+testit "Query ACL with four entries" $CMD --view ||
+ failed=$(expr $failed + 1)
+COUNT=$($CMD --view | grep ACL: | sed -e 's/^ACL://' | wc -l)
+testit "Verify ACL count with four entries" test $COUNT -eq 4 ||
+ failed=$(expr $failed + 1)
+ACL=$($CMD --view | grep S-1-5-32-546 | sed -e 's/^ACL://')
+testit "Verify special entry" test $ACL = S-1-5-32-546:ALLOWED/0x0/RWXDP ||
+ failed=$(expr $failed + 1)
+
+testit "Remove ACL entry" $CMD --remove S-1-5-32-546:ALLOWED/0x0/RWXDP ||
+ failed=$(expr $failed + 1)
+testit "Query ACL with three entries after removal" $CMD --view ||
+ failed=$(expr $failed + 1)
+COUNT=$($CMD --view | grep ACL: | sed -e 's/^ACL://' | wc -l)
+testit "Verify ACL count after removal" test $COUNT -eq 3 ||
+ failed=$(expr $failed + 1)
+ACL="$($CMD --view | grep S-1-5-32-546)"
+testit "Verify removal" test -e "$ACL" || failed=$(expr $failed + 1)
+
+testit "Set ACL as hex value" $CMD --add S-1-5-32-547:0x1/0x0/0x001F01FF ||
+ failed=$(expr $failed + 1)
+ACL="$($CMD --view | grep S-1-5-32-547 | sed -e 's/^ACL://')"
+testit "Verify numerically set entry" \
+ test "$ACL" = S-1-5-32-547:DENIED/0x0/FULL ||
+ failed=$(expr $failed + 1)
+
+testit "Set ACL as dec value" $CMD --add S-1-5-32-548:1/0/0x001F01FF ||
+ failed=$(expr $failed + 1)
+ACL="$($CMD --view | grep S-1-5-32-548 | sed -e 's/^ACL://')"
+testit "Verify numerically set entry" \
+ test "$ACL" = S-1-5-32-548:DENIED/0x0/FULL ||
+ failed=$(expr $failed + 1)
+
+testit "Set back to default ACL " $CMD --replace S-1-1-0:ALLOWED/0x0/FULL ||
+ failed=$(expr $failed + 1)
+testit "Query standard ACL" $CMD --view ||
+ failed=$(expr $failed + 1)
+COUNT=$($CMD --view | grep ACL: | sed -e 's/^ACL://' | wc -l)
+testit "Verify standard ACL count" test $COUNT -eq 1 ||
+ failed=$(expr $failed + 1)
+ACL=$($CMD --view | grep ACL: | sed -e 's/^ACL://')
+testit "Verify standard ACL" test $ACL = S-1-1-0:ALLOWED/0x0/FULL ||
+ failed=$(expr $failed + 1)
+
+testit "Create new share" $NET_CMD conf addshare tmp_share /tmp ||
+ failed=$(expr $failed + 1)
+testit "Change ACL" $SHARESEC $CONF --replace S-1-1-0:DENIED/0x0/FULL tmp_share ||
+ failed=$(expr $failed + 1)
+testit "Delete share" $NET_CMD conf delshare tmp_share ||
+ failed=$(expr $failed + 1)
+testit "Create share again" $NET_CMD conf addshare tmp_share /tmp ||
+ failed=$(expr $failed + 1)
+ACL=$($SHARESEC $CONF --view tmp_share | grep 'ACL:')
+testit "Check for default ACL" \
+ test "$ACL" = "ACL:S-1-1-0:ALLOWED/0x0/FULL" ||
+ failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_smb1_shadow_copy_torture.sh b/source3/script/tests/test_smb1_shadow_copy_torture.sh
new file mode 100755
index 0000000..3ea3030
--- /dev/null
+++ b/source3/script/tests/test_smb1_shadow_copy_torture.sh
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+#
+# Blackbox test for shadow_copy2 VFS - SMB1 only.
+#
+
+if [ $# -lt 7 ]; then
+ cat <<EOF
+Usage: test_shadow_copy SERVER SERVER_IP DOMAIN USERNAME PASSWORD WORKDIR SMBTORTURE
+EOF
+ exit 1
+fi
+
+SERVER=${1}
+SERVER_IP=${2}
+DOMAIN=${3}
+USERNAME=${4}
+PASSWORD=${5}
+WORKDIR=${6}
+SMBTORTURE="$VALGRIND ${7}"
+shift 7
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+SNAPSHOT="@GMT-2015.10.31-19.40.30"
+
+failed=0
+
+cd $SELFTEST_TMPDIR || exit 1
+
+# build a hierarchy of files, symlinks, and directories
+build_files()
+{
+ local destdir
+ destdir=$1
+
+ echo "$content" >$destdir/foo
+}
+
+# build a snapshots directory
+build_snapshots()
+{
+ local snapdir
+
+ snapdir=$WORKDIR/.snapshots
+
+ mkdir -p $snapdir
+ mkdir $snapdir/$SNAPSHOT
+
+ build_files $snapdir/$SNAPSHOT
+}
+
+test_shadow_copy_openroot()
+{
+ local msg
+
+ msg=$1
+
+ #delete snapshots from previous tests
+ find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
+ build_snapshots
+
+ testit "opening shadow copy root of share over SMB1" \
+ $SMBTORTURE \
+ -U$USERNAME%$PASSWORD \
+ "//$SERVER/shadow_write" \
+ --option="torture:twrp_snapshot=$SNAPSHOT" \
+ base.smb1-twrp-openroot ||
+ failed=$(expr $failed + 1)
+}
+
+build_files $WORKDIR
+
+# test open for writing and write behaviour of snapshoted files
+test_shadow_copy_openroot "opening root of shadow copy share"
+
+exit $failed
diff --git a/source3/script/tests/test_smb1_system_security.sh b/source3/script/tests/test_smb1_system_security.sh
new file mode 100755
index 0000000..dac8897
--- /dev/null
+++ b/source3/script/tests/test_smb1_system_security.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+#
+# Runs the smbtorture3 SMB1-SYSTEM-SECURITY test
+# that requires SeSecurityPrivilege against Samba.
+#
+
+if [ $# -lt 7 ]; then
+ echo "Usage: $0 SERVER SERVER_IP USERNAME PASSWORD SMBTORTURE3 NET SHARE"
+ exit 1
+fi
+
+SERVER="$1"
+SERVER_IP="$2"
+USERNAME="$3"
+PASSWORD="$4"
+SMBTORTURE3="$5"
+NET="$6"
+SHARE="$7"
+
+failed=0
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+smb1_system_security()
+{
+ out=$($SMBTORTURE3 //$SERVER_IP/$SHARE -U $USERNAME%$PASSWORD -mNT1 SMB1-SYSTEM-SECURITY)
+ if [ $? -ne 0 ]; then
+ echo "SMB1-SYSTEM-SECURITY failed"
+ echo "$out"
+ return 1
+ fi
+}
+
+# Grant SeSecurityPrivilege to the user
+testit "grant SeSecurityPrivilege" $NET rpc rights grant $USERNAME SeSecurityPrivilege -U $USERNAME%$PASSWORD -I $SERVER_IP || failed=$(expr $failed + 1)
+
+# Run the test.
+testit "smb1-system-security" smb1_system_security || failed=$(expr $failed + 1)
+
+# Revoke SeSecurityPrivilege
+testit "revoke SeSecurityPrivilege" $NET rpc rights revoke $USERNAME SeSecurityPrivilege -U $USERNAME%$PASSWORD -I $SERVER_IP || failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source3/script/tests/test_smb2_not_casesensitive.sh b/source3/script/tests/test_smb2_not_casesensitive.sh
new file mode 100755
index 0000000..7e85834
--- /dev/null
+++ b/source3/script/tests/test_smb2_not_casesensitive.sh
@@ -0,0 +1,81 @@
+#!/bin/sh
+#
+# Blackbox test for SMB2 case insensitivity
+#
+
+if [ $# -lt 6 ]; then
+ cat <<EOF
+Usage: test_smb2_not_casesensitive SERVER SERVER_IP USERNAME PASSWORD LOCAL_PATH SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER=${1}
+SERVER_IP=${2}
+USERNAME=${3}
+PASSWORD=${4}
+LOCAL_PATH=${5}
+SMBCLIENT=${6}
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+# Test a file with different case works over SMB2 and later
+test_access_with_different_case()
+{
+ tmpfile=$LOCAL_PATH/testfile.txt
+ echo "foobar" >$tmpfile
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -mSMB3 -U$USERNAME%$PASSWORD "$SERVER" -I $SERVER_IP -c "ls TeStFiLe.TxT" 2>&1'
+ out=$(eval $cmd)
+ ret=$?
+
+ rm -f $tmpfile
+
+ if [ $ret = 0 ]; then
+ return 0
+ else
+ echo "$out"
+ echo "failed to get file with different case"
+ return 1
+ fi
+}
+
+# Test that a rename causes a conflict works when target name exists in
+# different case
+test_rename()
+{
+ set -x
+ tmpfile=$LOCAL_PATH/torename.txt
+ echo "foobar" >$tmpfile
+ targetfile=$LOCAL_PATH/target.txt
+ touch $targetfile
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -mSMB3 -U$USERNAME%$PASSWORD "$SERVER" -I $SERVER_IP -c "rename ToReNaMe.TxT TaRgEt.txt" 2>&1'
+ out=$(eval $cmd)
+ ret=$?
+
+ rm -f $tmpfile
+ rm -f $targetfile
+ rm -f $LOCAL_PATH/TaRgEt.txt
+
+ if [ $ret = 1 -a -z "${out##*COLLISION*}" ]; then
+ return 0
+ else
+ echo "$out"
+ echo "failed to get file with different case"
+ return 1
+ fi
+}
+
+testit "accessing a file with different case succeeds" \
+ test_access_with_different_case ||
+ failed=$(expr $failed + 1)
+
+testit "renaming a file with different case succeeds" \
+ test_rename ||
+ failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source3/script/tests/test_smbXsrv_client_cross_node.sh b/source3/script/tests/test_smbXsrv_client_cross_node.sh
new file mode 100755
index 0000000..5b412b2
--- /dev/null
+++ b/source3/script/tests/test_smbXsrv_client_cross_node.sh
@@ -0,0 +1,92 @@
+#!/usr/bin/env bash
+#
+# Test smbd let cluster node 0 destroy the connection,
+# if the client with a specific client-guid connections to node 1
+#
+
+if [ $# -lt 4 ]; then
+ echo Usage: test_smbXsrv_client_cross_node.sh SERVERCONFFILE NODE0 NODE1 SHARENAME
+ exit 1
+fi
+
+CONF=$1
+NODE0=$2
+NODE1=$3
+SHARE=$4
+
+SMBCLIENT="$BINDIR/smbclient"
+SMBSTATUS="$BINDIR/smbstatus"
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir"/subunit.sh
+
+failed=0
+
+test_smbclient()
+{
+ name="$1"
+ server="$2"
+ share="$3"
+ cmd="$4"
+ shift
+ shift
+ subunit_start_test "$name"
+ output=$($VALGRIND $SMBCLIENT //$server/$share -c "$cmd" "$@" 2>&1)
+ status=$?
+ if [ x$status = x0 ]; then
+ subunit_pass_test "$name"
+ else
+ echo "$output" | subunit_fail_test "$name"
+ fi
+ return $status
+}
+
+cd "$SELFTEST_TMPDIR" || exit 1
+
+# Create the smbclient communication pipes.
+rm -f smbclient-stdin smbclient-stdout smbclient-stderr
+mkfifo smbclient-stdin smbclient-stdout smbclient-stderr
+
+smbstatus_num_sessions()
+{
+ UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 "$SMBSTATUS" "$CONF" --json | jq -M '.sessions | length'
+}
+
+testit_grep "step1: smbstatus 0 sessions" '^0$' smbstatus_num_sessions || failed=$(expr $failed + 1)
+
+test_smbclient "smbclient against node0[${NODE0}]" "${NODE0}" "${SHARE}" "ls" -U"${DC_USERNAME}"%"${DC_PASSWORD}" \
+ --option="libsmb:client_guid=6112f7d3-9528-4a2a-8861-0ca129aae6c4" \
+ || failed=$(expr $failed + 1)
+
+testit_grep "step2: smbstatus 0 sessions" '^0$' smbstatus_num_sessions || failed=$(expr $failed + 1)
+
+CLI_FORCE_INTERACTIVE=1
+export CLI_FORCE_INTERACTIVE
+
+testit "start backgroup smbclient against node0[${NODE0}]" true || failed=$(expr $failed + 1)
+
+# Connect a first time
+${SMBCLIENT} //"${NODE0}"/"${SHARE}" -U"${DC_USERNAME}"%"${DC_PASSWORD}" \
+ --option="libsmb:client_guid=6112f7d3-9528-4a2a-8861-0ca129aae6c4" \
+ <smbclient-stdin >smbclient-stdout 2>smbclient-stderr &
+CLIENT_PID=$!
+
+exec 100>smbclient-stdin 101<smbclient-stdout 102<smbclient-stderr
+
+testit "sleep 1 second" true || failed=$(expr $failed + 1)
+sleep 1
+
+testit_grep "step3: smbstatus 1 session" '^1$' smbstatus_num_sessions || failed=$(expr $failed + 1)
+
+# Connect a second time
+unset CLI_FORCE_INTERACTIVE
+test_smbclient "smbclient against node1[${NODE1}]" "${NODE1}" "${SHARE}" "ls" -U"${DC_USERNAME}"%"${DC_PASSWORD}" \
+ --option="libsmb:client_guid=6112f7d3-9528-4a2a-8861-0ca129aae6c4" \
+ || failed=$(expr $failed + 1)
+
+kill $CLIENT_PID
+rm -f smbclient-stdin smbclient-stdout smbclient-stderr
+
+testit_grep "step24: smbstatus 0 sessions" '^0$' smbstatus_num_sessions || failed=$(expr $failed + 1)
+
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_smbXsrv_client_ctdb_registered_ips.sh b/source3/script/tests/test_smbXsrv_client_ctdb_registered_ips.sh
new file mode 100755
index 0000000..025a0fa
--- /dev/null
+++ b/source3/script/tests/test_smbXsrv_client_ctdb_registered_ips.sh
@@ -0,0 +1,159 @@
+#!/usr/bin/env bash
+#
+# Test smbd let cleanup registered ip addresses in a multichannel
+# scenario
+#
+
+if [ $# -lt 3 ]; then
+ echo Usage: test_smbXsrv_client_ctdb_registered_ips.sh SERVERCONFFILE CTDB_IFACE_IP SHARENAME
+ exit 1
+fi
+
+CONF=$1
+CTDB_IFACE_IP=$2
+SHARE=$3
+
+SMBCLIENT="$BINDIR/smbclient"
+SMBSTATUS="$BINDIR/smbstatus"
+CTDB="$BINDIR/ctdb"
+TIMELIMIT="$BINDIR/timelimit"
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir"/subunit.sh
+
+failed=0
+
+test_smbclient()
+{
+ name="$1"
+ server="$2"
+ share="$3"
+ cmd="$4"
+ shift
+ shift
+ subunit_start_test "$name"
+ output=$($VALGRIND $SMBCLIENT //$server/$share -c "$cmd" "$@" 2>&1)
+ status=$?
+ if [ x$status = x0 ]; then
+ subunit_pass_test "$name"
+ else
+ echo "$output" | subunit_fail_test "$name"
+ fi
+ return $status
+}
+
+cd "$SELFTEST_TMPDIR" || exit 1
+
+# Create the smbclient communication pipes.
+rm -f smbclient1-stdin smbclient1-stdout smbclient1-stderr
+mkfifo smbclient1-stdin smbclient1-stdout smbclient1-stderr
+rm -f smbclient2-stdin smbclient2-stdout smbclient2-stderr
+mkfifo smbclient2-stdin smbclient2-stdout smbclient2-stderr
+
+smbstatus_num_sessions()
+{
+ # We don't check for died processes
+ UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 "$SMBSTATUS" "$CONF" --fast --json | jq -M '.sessions | length'
+}
+
+ctdb_add_public_ip()
+{
+ UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 "$CTDB" addip ${CTDB_IFACE_IP}/24 lo
+ UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 "$CTDB" ipreallocate
+}
+
+ctdb_ip()
+{
+ UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 "$CTDB" ip
+}
+
+ctdb_gettickles()
+{
+ UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 "$CTDB" gettickles ${CTDB_IFACE_IP}
+}
+
+ctdb_reload_public_ips()
+{
+ UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 "$CTDB" reloadips 0
+ UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 "$CTDB" ipreallocate
+}
+
+testit_grep_count "step1: smbstatus 0 sessions" '^0$' 1 smbstatus_num_sessions || failed=$(expr $failed + 1)
+
+test_smbclient "step2: smbclient against node0[${CTDB_IFACE_IP}]" "${CTDB_IFACE_IP}" "${SHARE}" "ls" -U"${DC_USERNAME}"%"${DC_PASSWORD}" \
+ --option="libsmb:client_guid=6112f7d3-9528-4a2a-8861-0ca129aae6c4" \
+ || failed=$(expr $failed + 1)
+
+testit_grep_count "step2: smbstatus 0 sessions" '^0$' 1 smbstatus_num_sessions || failed=$(expr $failed + 1)
+
+CLI_FORCE_INTERACTIVE=1
+export CLI_FORCE_INTERACTIVE
+
+testit "step3: start backgroup smbclient against node0[${CTDB_IFACE_IP}]" true || failed=$(expr $failed + 1)
+
+# Connect a first time
+${SMBCLIENT} //"${CTDB_IFACE_IP}"/"${SHARE}" -U"${DC_USERNAME}"%"${DC_PASSWORD}" \
+ --option="libsmb:client_guid=6112f7d3-9528-4a2a-8861-0ca129aae6c4" \
+ <smbclient1-stdin >smbclient1-stdout 2>smbclient1-stderr &
+CLIENT1_PID=$!
+
+exec 100>smbclient1-stdin 101<smbclient1-stdout 102<smbclient1-stderr
+
+testit_grep_count "step3: smbclient1-stdout" 'Try "help" to get a list of possible commands.' 1 $TIMELIMIT 15 head -1 smbclient1-stdout || failed=$(expr $failed + 1)
+
+testit_grep_count "step3: smbstatus 1 session" '^1$' 1 smbstatus_num_sessions || failed=$(expr $failed + 1)
+
+testit_grep_count "step3: ctdb_ip" "${CTDB_IFACE_IP}" 0 ctdb_ip || failed=$(expr $failed + 1)
+testit_expect_failure_grep "step3: ctdb_gettickles" "Control GET_TCP_TICKLE_LIST failed" ctdb_gettickles || failed=$(expr $failed + 1)
+
+testit "step4: ctdb_add_public_ip" ctdb_add_public_ip || failed=$(expr $failed + 1)
+
+testit_grep_count "step4: ctdb_ip" "^${CTDB_IFACE_IP} 0\$" 1 ctdb_ip || failed=$(expr $failed + 1)
+testit_grep_count "step4: ctdb_gettickles" "Num connections: 0" 1 ctdb_gettickles || failed=$(expr $failed + 1)
+
+testit "step5: start backgroup 2nd smbclient against node0[${CTDB_IFACE_IP}]" true || failed=$(expr $failed + 1)
+# Connect a second time
+${SMBCLIENT} //"${CTDB_IFACE_IP}"/"${SHARE}" -U"${DC_USERNAME}"%"${DC_PASSWORD}" \
+ --option="libsmb:client_guid=6112f7d3-9528-4a2a-8861-0ca129aae6c4" \
+ <smbclient2-stdin >smbclient2-stdout 2>smbclient2-stderr &
+CLIENT2_PID=$!
+
+exec 200>smbclient2-stdin 201<smbclient2-stdout 202<smbclient2-stderr
+
+testit_grep_count "step5: smbclient2-stdout" 'Try "help" to get a list of possible commands.' 1 $TIMELIMIT 15 head -1 smbclient2-stdout || failed=$(expr $failed + 1)
+
+testit_grep_count "step5: smbstatus 2 session" '^2$' 1 smbstatus_num_sessions || failed=$(expr $failed + 1)
+
+# Only one connection was registered with the public address
+testit_grep_count "step5: ctdb_ip" "^${CTDB_IFACE_IP} 0\$" 1 ctdb_ip || failed=$(expr $failed + 1)
+testit_grep_count "step5: ctdb_gettickles NUM" "Num connections: 1" 1 ctdb_gettickles || failed=$(expr $failed + 1)
+testit_grep_count "step5: ctdb_gettickles DST" "DST: ${CTDB_IFACE_IP}" 1 ctdb_gettickles || failed=$(expr $failed + 1)
+
+unset CLI_FORCE_INTERACTIVE
+
+kill $CLIENT1_PID
+rm -f smbclient1-stdin smbclient1-stdout smbclient1-stderr
+
+testit "step6: sleep 1 second" true || failed=$(expr $failed + 1)
+sleep 1
+
+testit_grep_count "step6: smbstatus 1 session" '^1$' 1 smbstatus_num_sessions || failed=$(expr $failed + 1)
+
+testit_grep_count "step6: ctdb_ip" "^${CTDB_IFACE_IP} 0\$" 1 ctdb_ip || failed=$(expr $failed + 1)
+testit_grep_count "step6: ctdb_gettickles NUM" "Num connections: 1" 1 ctdb_gettickles || failed=$(expr $failed + 1)
+testit_grep_count "step6: ctdb_gettickles DST" "DST: ${CTDB_IFACE_IP}" 1 ctdb_gettickles || failed=$(expr $failed + 1)
+
+testit "step7: ctdb_reload_public_ips" ctdb_reload_public_ips || failed=$(expr $failed + 1)
+
+testit_grep_count "step7: ctdb_ip" "${CTDB_IFACE_IP}" 0 ctdb_ip || failed=$(expr $failed + 1)
+testit_expect_failure_grep "step3: ctdb_gettickles" "Control GET_TCP_TICKLE_LIST failed" ctdb_gettickles || failed=$(expr $failed + 1)
+
+testit "step7: sleep 2 second" true || failed=$(expr $failed + 1)
+sleep 2
+
+testit_grep_count "step7: smbstatus 0 sessions" '^0$' 1 smbstatus_num_sessions || failed=$(expr $failed + 1)
+
+kill $CLIENT2_PID
+rm -f smbclient2-stdin smbclient2-stdout smbclient2-stderr
+
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_smbXsrv_client_dead_rec.sh b/source3/script/tests/test_smbXsrv_client_dead_rec.sh
new file mode 100755
index 0000000..e9e8f77
--- /dev/null
+++ b/source3/script/tests/test_smbXsrv_client_dead_rec.sh
@@ -0,0 +1,76 @@
+#!/usr/bin/env bash
+#
+# Test smbd doesn't crash if there an existing dead record for a client with a
+# specific client-guid in smbXsrv_client_global.tdb
+#
+
+if [ $# -lt 2 ]; then
+ echo Usage: test_smbXsrv_client_dead_rec.sh SERVERCONFFILE IP SHARENAME
+ exit 1
+fi
+
+CONF=$1
+SERVER=$2
+SHARE=$3
+
+SMBCLIENT="$BINDIR/smbclient"
+SMBSTATUS="$BINDIR/smbstatus"
+
+SMBD_LOG_FILE="$SMBD_TEST_LOG"
+if [ -n "$SMBD_DONT_LOG_STDOUT" ]; then
+ SMBD_LOG_FILE=$(dirname "$SMBD_TEST_LOG")/logs/log.smbd
+fi
+SMBD_LOG_FILE=$(realpath "$SMBD_LOG_FILE")
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir"/subunit.sh
+
+failed=0
+
+cd "$SELFTEST_TMPDIR" || exit 1
+
+#
+# Note if we already have any panics in the smbd log.
+#
+panic_count_0=$(grep -c PANIC "$SMBD_LOG_FILE")
+
+# Create the smbclient communication pipes.
+rm -f smbclient-stdin smbclient-stdout smbclient-stderr
+mkfifo smbclient-stdin smbclient-stdout smbclient-stderr
+
+CLI_FORCE_INTERACTIVE=1
+export CLI_FORCE_INTERACTIVE
+
+# Connect a first time
+${SMBCLIENT} //"${SERVER}"/"${SHARE}" -U"${USER}"%"${PASSWORD}" \
+ --option="libsmb:client_guid=6112f7d3-9528-4a2a-8861-0ca129aae6c4" \
+ <smbclient-stdin >smbclient-stdout 2>smbclient-stderr &
+CLIENT_PID=$!
+
+exec 100>smbclient-stdin 101<smbclient-stdout 102<smbclient-stderr
+
+SMBD_PID=$(UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 "$SMBSTATUS" -p "$CONF" | awk '/^[0-9]+/ {print $1}' | sort -u)
+
+# Kill the first connection, leaves dead record in smbXsrv_client_global.tdb
+kill -KILL "$SMBD_PID"
+kill $CLIENT_PID
+
+# Connect a second time
+unset CLI_FORCE_INTERACTIVE
+${SMBCLIENT} //"${SERVER}"/"${SHARE}" -U"${USER}"%"${PASSWORD}" \
+ --option="libsmb:client_guid=6112f7d3-9528-4a2a-8861-0ca129aae6c4" \
+ -c exit
+
+rm -f smbclient-stdin smbclient-stdout smbclient-stderr
+
+#
+# Ensure the panic count didn't change.
+#
+# BUG: https://bugzilla.samba.org/show_bug.cgi?id=14882
+#
+panic_count_1=$(grep -c PANIC "$SMBD_LOG_FILE")
+
+testit "check_panic" test "$panic_count_0" -eq "$panic_count_1" ||
+ failed=$(expr $failed + 1)
+
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_smbclient_auth.sh b/source3/script/tests/test_smbclient_auth.sh
new file mode 100755
index 0000000..c6dcfc3
--- /dev/null
+++ b/source3/script/tests/test_smbclient_auth.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+# this runs the file serving tests that are expected to pass with samba3 against shares with various options
+
+if [ $# -lt 5 ]; then
+ cat <<EOF
+Usage: test_smbclient_auth.sh SERVER SERVER_IP USERNAME PASSWORD SMBCLIENT <smbclient arguments>
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+SERVER_IP="$2"
+USERNAME="$3"
+PASSWORD="$4"
+SMBCLIENT="$5"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+shift 5
+ADDARGS="$*"
+
+failed=0
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+echo "${SERVER_IP}" | grep -q ':.*:' && {
+ # If we have an ipv6 address e.g.
+ # fd00:0000:0000:0000:0000:0000:5357:5f03
+ # we also try
+ # fd00-0000-0000-0000-0000-0000-5357-5f03.ipv6-literal.net
+ IPV6LITERAL=$(echo "${SERVER_IP}.ipv6-literal.net" | sed -e 's!:!-!g' -e 's!%!s!')
+ testit "smbclient //${IPV6LITERAL}/tmpguest as user" $SMBCLIENT //${IPV6LITERAL}/tmpguest $CONFIGURATION -U$USERNAME%$PASSWORD -c quit $ADDARGS || failed=$(expr $failed + 1)
+ testit "smbclient //${IPV6LITERAL}./tmpguest as user" $SMBCLIENT //${IPV6LITERAL}./tmpguest $CONFIGURATION -U$USERNAME%$PASSWORD -c quit $ADDARGS || failed=$(expr $failed + 1)
+}
+testit "smbclient //${SERVER_IP}/tmpguest as user" $SMBCLIENT //${SERVER_IP}/tmpguest $CONFIGURATION -U$USERNAME%$PASSWORD -p 139 -c quit $ADDARGS || failed=$(expr $failed + 1)
+
+testit "smbclient //$SERVER/guestonly as user" $SMBCLIENT //$SERVER/guestonly $CONFIGURATION -U$USERNAME%$PASSWORD -I $SERVER_IP -p 139 -c quit $ADDARGS || failed=$(expr $failed + 1)
+testit "smbclient //$SERVER/guestonly as anon" $SMBCLIENT //$SERVER/guestonly $CONFIGURATION -U% -I $SERVER_IP -p 139 -c quit $ADDARGS || failed=$(expr $failed + 1)
+testit "smbclient //$SERVER/tmpguest as user" $SMBCLIENT //$SERVER/tmpguest $CONFIGURATION -U$USERNAME%$PASSWORD -I $SERVER_IP -p 139 -c quit $ADDARGS || failed=$(expr $failed + 1)
+testit "smbclient //$SERVER/tmpguest as anon" $SMBCLIENT //$SERVER/tmpguest $CONFIGURATION -U% -I $SERVER_IP -p 139 -c quit $ADDARGS || failed=$(expr $failed + 1)
+testit "smbclient //$SERVER/forceuser as user" $SMBCLIENT //$SERVER/forceuser $CONFIGURATION -U$USERNAME%$PASSWORD -I $SERVER_IP -p 139 -c quit $ADDARGS || failed=$(expr $failed + 1)
+testit "smbclient //$SERVER/forceuser as anon" $SMBCLIENT //$SERVER/forceuser $CONFIGURATION -U% -I $SERVER_IP -p 139 -c quit $ADDARGS || failed=$(expr $failed + 1)
+testit "smbclient //$SERVER/forceuser_unixonly as user" $SMBCLIENT //$SERVER/forceuser_unixonly $CONFIGURATION -U$USERNAME%$PASSWORD -I $SERVER_IP -p 139 -c quit $ADDARGS || failed=$(expr $failed + 1)
+testit "smbclient //$SERVER/forceuser_wkngroup as user" $SMBCLIENT //$SERVER/forceuser_wkngroup $CONFIGURATION -U$USERNAME%$PASSWORD -I $SERVER_IP -p 139 -c quit $ADDARGS || failed=$(expr $failed + 1)
+testit "smbclient //$SERVER/forcegroup as user" $SMBCLIENT //$SERVER/forcegroup $CONFIGURATION -U$USERNAME%$PASSWORD -I $SERVER_IP -p 139 -c quit $ADDARGS || failed=$(expr $failed + 1)
+testit "smbclient //$SERVER/forcegroup as anon" $SMBCLIENT //$SERVER/forcegroup $CONFIGURATION -U% -I $SERVER_IP -p 139 -c quit $ADDARGS || failed=$(expr $failed + 1)
+exit $failed
diff --git a/source3/script/tests/test_smbclient_basic.sh b/source3/script/tests/test_smbclient_basic.sh
new file mode 100755
index 0000000..6e2a17c
--- /dev/null
+++ b/source3/script/tests/test_smbclient_basic.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+# this runs the file serving tests that are expected to pass with samba3 against shares with various options
+
+if [ $# -lt 5 ]; then
+ cat <<EOF
+Usage: test_smbclient_basic.sh SERVER SERVER_IP DOMAIN USERNAME PASSWORD SMBCLIENT <smbclient arguments>
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+SERVER_IP="$2"
+USERNAME="$3"
+PASSWORD="$4"
+smbclient="$5"
+CONFIGURATION="$6"
+shift 6
+ADDARGS="$@"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+. $incdir/common_test_fns.inc
+
+# TEST using \ as the separator (default)
+test_smbclient "smbclient as $DOMAIN\\$USERNAME" 'ls' "//$SERVER/tmp" -U$DOMAIN\\$USERNAME%$PASSWORD $ADDARGS || failed=$(expr $failed + 1)
+# TEST using / as the separator (default)
+test_smbclient "smbclient as $DOMAIN/$USERNAME" 'ls' "//$SERVER/tmp" -U$DOMAIN/$USERNAME%$PASSWORD $ADDARGS || failed=$(expr $failed + 1)
+
+# TEST using 'winbind separator = +'
+test_smbclient "smbclient as $DOMAIN+$USERNAME" 'ls' "//$SERVER/tmp" -U$DOMAIN+$USERNAME%$PASSWORD $ADDARGS --option=winbindseparator=+ || failed=$(expr $failed + 1)
+
+# TEST using 'winbind separator = +' set in a config file
+smbclient_config="$PREFIX/tmpsmbconf"
+cat >$smbclient_config <<EOF
+[global]
+ include = $(echo $CONFIGURATION | cut -d= -f2)
+ winbind separator = +
+EOF
+
+SAVE_CONFIGURATION="$CONFIGURATION"
+CONFIGURATION="--configfile=$smbclient_config"
+test_smbclient "smbclient as $DOMAIN+$USERNAME" 'ls' "//$SERVER/tmp" -U$DOMAIN+$USERNAME%$PASSWORD $ADDARGS || failed=$(expr $failed + 1)
+CONFIGURATION="$SAVE_CONFIGURATION"
+rm -rf $smbclient_config
+
+exit $failed
diff --git a/source3/script/tests/test_smbclient_encryption.sh b/source3/script/tests/test_smbclient_encryption.sh
new file mode 100755
index 0000000..2cbf5f0
--- /dev/null
+++ b/source3/script/tests/test_smbclient_encryption.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+if [ $# -lt 5 ]; then
+ cat <<EOF
+Usage: test_smbclient_encryption.sh USERNAME PASSWORD SERVER SMBCLIENT TARGET
+EOF
+ exit 1
+fi
+
+USERNAME="$1"
+PASSWORD="$2"
+SERVER="$3"
+SMBCLIENT="$VALGRIND $4"
+TARGET="$5"
+shift 5
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+#
+# Server configuration for fileserver:
+#
+# global: 'server smb encrypt = default'
+# enc_desired: 'server smb encrypt = desired'
+# tmpenc: 'server smb encrypt = required'
+# tmp: has the global default 'server smb encrypt'
+#
+# Server configuration for simpleserver:
+#
+# global: 'server smb encrypt = off'
+# enc_desired: 'server smb encrypt = desired'
+# tmpenc: 'server smb encrypt = required'
+# tmp: has the global default 'server smb encrypt'
+#
+
+testit "smbclient.smb3.client.encrypt.desired[//$SERVER/enc_desired]" $SMBCLIENT //$SERVER/enc_desired -U$USERNAME%$PASSWORD -mSMB3 --option=clientsmbencrypt=desired -c 'ls; quit' || failed=$(expr $failed + 1)
+if [ "$TARGET" = "fileserver" ]; then
+ testit "smbclient.smb3.client.encrypt.desired[//$SERVER/tmpenc]" $SMBCLIENT //$SERVER/tmpenc -U$USERNAME%$PASSWORD -mSMB3 --option=clientsmbencrypt=desired -c 'ls; quit' || failed=$(expr $failed + 1)
+elif [ "$TARGET" = "simpleserver" ]; then # Encryption is globally disabled
+ testit_expect_failure "smbclient.smb3.client.encrypt.desired[//$SERVER/tmpenc]" $SMBCLIENT //$SERVER/tmpenc -U$USERNAME%$PASSWORD -mSMB3 --option=clientsmbencrypt=desired -c 'ls; quit' || failed=$(expr $failed + 1)
+fi
+testit "smbclient.smb3.client.encrypt.desired[//$SERVER/tmp]" $SMBCLIENT //$SERVER/tmp -U$USERNAME%$PASSWORD -mSMB3 --option=clientsmbencrypt=desired -c 'ls; quit' || failed=$(expr $failed + 1)
+
+testit "smbclient.smb3.client.encrypt.if_required[//$SERVER/enc_desired]" $SMBCLIENT //$SERVER/enc_desired -U$USERNAME%$PASSWORD -mSMB3 --option=clientsmbencrypt=if_required -c 'ls; quit' || failed=$(expr $failed + 1)
+if [ "$TARGET" = "fileserver" ]; then
+ testit "smbclient.smb3.client.encrypt.if_required[//$SERVER/tmpenc]" $SMBCLIENT //$SERVER/tmpenc -U$USERNAME%$PASSWORD -mSMB3 --option=clientsmbencrypt=if_required -c 'ls; quit' || failed=$(expr $failed + 1)
+elif [ "$TARGET" = "simpleserver" ]; then # Encryption is globally disabled
+ testit_expect_failure "smbclient.smb3.client.encrypt.if_required[//$SERVER/tmpenc]" $SMBCLIENT //$SERVER/tmpenc -U$USERNAME%$PASSWORD -mSMB3 --option=clientsmbencrypt=if_required -c 'ls; quit' || failed=$(expr $failed + 1)
+fi
+testit "smbclient.smb3.client.encrypt.if_required[//$SERVER/tmp]" $SMBCLIENT //$SERVER/tmp -U$USERNAME%$PASSWORD -mSMB3 --option=clientsmbencrypt=if_required -c 'ls; quit' || failed=$(expr $failed + 1)
+
+if [ "$TARGET" = "fileserver" ]; then
+ testit "smbclient.smb3.client.encrypt.required[//$SERVER/enc_desired]" $SMBCLIENT //$SERVER/enc_desired -U$USERNAME%$PASSWORD -mSMB3 --option=clientsmbencrypt=required -c 'ls; quit' || failed=$(expr $failed + 1)
+ testit "smbclient.smb3.client.encrypt.required[//$SERVER/tmpenc]" $SMBCLIENT //$SERVER/tmpenc -U$USERNAME%$PASSWORD -mSMB3 --option=clientsmbencrypt=required -c 'ls; quit' || failed=$(expr $failed + 1)
+ testit "smbclient.smb3.client.encrypt.required[//$SERVER/tmp]" $SMBCLIENT //$SERVER/tmp -U$USERNAME%$PASSWORD -mSMB3 --option=clientsmbencrypt=required -c 'ls; quit' || failed=$(expr $failed + 1)
+elif [ "$TARGET" = "simpleserver" ]; then # Encryption is globally disabled
+ testit_expect_failure "smbclient.smb3.client.encrypt.required[//$SERVER/enc_desired]" $SMBCLIENT //$SERVER/enc_desired -U$USERNAME%$PASSWORD -mSMB3 --option=clientsmbencrypt=required -c 'ls; quit' || failed=$(expr $failed + 1)
+ testit_expect_failure "smbclient.smb3.client.encrypt.required[//$SERVER/tmpenc]" $SMBCLIENT //$SERVER/tmpenc -U$USERNAME%$PASSWORD -mSMB3 --option=clientsmbencrypt=required -c 'ls; quit' || failed=$(expr $failed + 1)
+ testit_expect_failure "smbclient.smb3.client.encrypt.required[//$SERVER/tmp]" $SMBCLIENT //$SERVER/tmp -U$USERNAME%$PASSWORD -mSMB3 --option=clientsmbencrypt=required -c 'ls; quit' || failed=$(expr $failed + 1)
+fi
+
+testit "smbclient.smb3.client.encrypt.off[//$SERVER/enc_desired]" $SMBCLIENT //$SERVER/enc_desired -U$USERNAME%$PASSWORD -mSMB3 --option=clientsmbencrypt=off -c 'ls; quit' || failed=$(expr $failed + 1)
+if [ "$TARGET" = "fileserver" ]; then
+ testit "smbclient.smb3.client.encrypt.off[//$SERVER/tmpenc]" $SMBCLIENT //$SERVER/tmpenc -U$USERNAME%$PASSWORD -mSMB3 --option=clientsmbencrypt=off -c 'ls; quit' || failed=$(expr $failed + 1)
+elif [ "$TARGET" = "simpleserver" ]; then # Encryption is globally disabled
+ testit_expect_failure "smbclient.smb3.client.encrypt.off[//$SERVER/tmpenc]" $SMBCLIENT //$SERVER/tmpenc -U$USERNAME%$PASSWORD -mSMB3 --option=clientsmbencrypt=off -c 'ls; quit' || failed=$(expr $failed + 1)
+fi
+testit "smbclient.smb3.client.encrypt.off[//$SERVER/tmp]" $SMBCLIENT //$SERVER/tmp -U$USERNAME%$PASSWORD -mSMB3 --option=clientsmbencrypt=off -c 'ls; quit' || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_smbclient_encryption_off.sh b/source3/script/tests/test_smbclient_encryption_off.sh
new file mode 100755
index 0000000..4bd99a0
--- /dev/null
+++ b/source3/script/tests/test_smbclient_encryption_off.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+
+if [ $# -lt 4 ]; then
+ cat <<EOF
+Usage: test_smbclient_encryption_off.sh USERNAME PASSWORD SERVER SMBCLIENT
+EOF
+ exit 1
+fi
+
+USERNAME="$1"
+PASSWORD="$2"
+SERVER="$3"
+SMBCLIENT="$VALGRIND $4"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+#
+# Let me introduce you to the shares used in this test:
+#
+# "tmp" has the default "smb encrypt" (which is "enabled")
+# "tmpenc" has "smb encrypt = required"
+# "enc_desired" has "smb encrypt = desired"
+#
+
+# Unencrypted connections should work of course, let's test em to be sure...
+
+# SMB1
+testit "smbclient //$SERVER/enc_desired" $SMBCLIENT -U $USERNAME%$PASSWORD //$SERVER/enc_desired -c quit || failed=$(expr $failed + 1)
+testit "smbclient //$SERVER/tmp" $SMBCLIENT -U $USERNAME%$PASSWORD //$SERVER/tmp -c quit || failed=$(expr $failed + 1)
+# SMB3_02
+testit "smbclient -m smb3_02 //$SERVER/enc_desired" $SMBCLIENT -m smb3_02 -U $USERNAME%$PASSWORD //$SERVER/enc_desired -c quit || failed=$(expr $failed + 1)
+testit "smbclient -m smb3_02 //$SERVER/tmp" $SMBCLIENT -m smb3_02 -U $USERNAME%$PASSWORD //$SERVER/tmp -c quit || failed=$(expr $failed + 1)
+# SMB3_11
+testit "smbclient -m smb3_11 //$SERVER/enc_desired" $SMBCLIENT -m smb3_11 -U $USERNAME%$PASSWORD //$SERVER/enc_desired -c quit || failed=$(expr $failed + 1)
+testit "smbclient -m smb3_11 //$SERVER/tmp" $SMBCLIENT -m smb3_11 -U $USERNAME%$PASSWORD //$SERVER/tmp -c quit || failed=$(expr $failed + 1)
+
+# These tests must fail, as encryption is globally off and in combination with "smb
+# encrypt=required" on the share "tmpenc" the server *must* reject the tcon.
+
+# SMB1
+testit_expect_failure "smbclient //$SERVER/tmpenc" $SMBCLIENT -U $USERNAME%$PASSWORD //$SERVER/tmpenc -c quit || failed=$(expr $failed + 1)
+testit_expect_failure "smbclient --client-protection=encrypt //$SERVER/tmpenc" $SMBCLIENT --client-protection=encrypt -U $USERNAME%$PASSWORD //$SERVER/tmpenc -c quit || failed=$(expr $failed + 1)
+# SMB3_02
+testit_expect_failure "smbclient -m smb3_02 //$SERVER/tmpenc" $SMBCLIENT -m smb3_02 -U $USERNAME%$PASSWORD //$SERVER/tmpenc -c quit || failed=$(expr $failed + 1)
+testit_expect_failure "smbclient --client-protection=encrypt -m smb3_02 //$SERVER/tmpenc" $SMBCLIENT --client-protection=encrypt -m smb3_02 -U $USERNAME%$PASSWORD //$SERVER/tmpenc -c quit || failed=$(expr $failed + 1)
+# SMB3_11
+testit_expect_failure "smbclient -m smb3_11 //$SERVER/tmpenc" $SMBCLIENT -m smb3_11 -U $USERNAME%$PASSWORD //$SERVER/tmpenc -c quit || failed=$(expr $failed + 1)
+testit_expect_failure "smbclient --client-protection=encrypt -m smb3_11 //$SERVER/tmpenc" $SMBCLIENT --client-protection=encrypt -m smb3_11 -U $USERNAME%$PASSWORD //$SERVER/tmpenc -c quit || failed=$(expr $failed + 1)
+
+# These tests must fail, as the client requires encryption and it's off on the server
+
+# SMB1
+testit_expect_failure "smbclient --client-protection=encrypt //$SERVER/enc_desired" $SMBCLIENT --client-protection=encrypt -U $USERNAME%$PASSWORD //$SERVER/enc_desired -c quit || failed=$(expr $failed + 1)
+testit_expect_failure "smbclient --client-protection=encrypt //$SERVER/tmp" $SMBCLIENT --client-protection=encrypt -U $USERNAME%$PASSWORD //$SERVER/tmp -c quit || failed=$(expr $failed + 1)
+# SMB3_02
+testit_expect_failure "smbclient --client-protection=encrypt -m smb3_02 //$SERVER/enc_desired" $SMBCLIENT --client-protection=encrypt -m smb3_02 -U $USERNAME%$PASSWORD //$SERVER/enc_desired -c quit || failed=$(expr $failed + 1)
+testit_expect_failure "smbclient --client-protection=encrypt -m smb3_02 //$SERVER/tmp" $SMBCLIENT --client-protection=encrypt -m smb3_02 -U $USERNAME%$PASSWORD //$SERVER/tmp -c quit || failed=$(expr $failed + 1)
+# SMB3_11
+testit_expect_failure "smbclient --client-protection=encrypt -m smb3_11 //$SERVER/enc_desired" $SMBCLIENT --client-protection=encrypt -m smb3_11 -U $USERNAME%$PASSWORD //$SERVER/enc_desired -c quit || failed=$(expr $failed + 1)
+testit_expect_failure "smbclient --client-protection=encrypt -m smb3_11 //$SERVER/tmp" $SMBCLIENT --client-protection=encrypt -m smb3_11 -U $USERNAME%$PASSWORD //$SERVER/tmp -c quit || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_smbclient_iconv.sh b/source3/script/tests/test_smbclient_iconv.sh
new file mode 100755
index 0000000..e6cdc5e
--- /dev/null
+++ b/source3/script/tests/test_smbclient_iconv.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+# This checks directory listing with a file containing
+# an invalid CP850 conversion name returns NT_STATUS_INVALID_NETWORK_RESPONSE
+
+if [ $# -lt 6 ]; then
+ cat <<EOF
+Usage: test_smbclient_iconv.sh SERVER SERVER_IP SHARENAME USERNAME PASSWORD SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+SERVER_IP="$2"
+SHARENAME="$3"
+USERNAME="$4"
+PASSWORD="$5"
+SMBCLIENT="$6"
+shift 6
+ADDARGS="$@"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+test_smbclient_iconv()
+{
+ normal_smbclient_config="$PREFIX/client/client.conf"
+ smbclient_config="$PREFIX/client/client_cp850_smbconf"
+ cat >$smbclient_config <<EOF
+[global]
+ include = $normal_smbclient_config
+ unix charset = cp850
+ client min protocol = core
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/$SHARENAME --configfile=$smbclient_config "$ADDARGS" -c ls 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ rm -f $smbclient_config
+
+ echo "$out" | grep 'NT_STATUS_INVALID_NETWORK_RESPONSE'
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo 'failed - should get: NT_STATUS_INVALID_NETWORK_RESPONSE.'
+ return 1
+ fi
+
+ return 0
+}
+
+testit "bad_iconv smbclient" test_smbclient_iconv || failed=$(expr $failed + 1)
+testok $0 $failed
diff --git a/source3/script/tests/test_smbclient_kerberos.sh b/source3/script/tests/test_smbclient_kerberos.sh
new file mode 100755
index 0000000..31678d1
--- /dev/null
+++ b/source3/script/tests/test_smbclient_kerberos.sh
@@ -0,0 +1,80 @@
+#!/bin/sh
+
+if [ $# -lt 6 ]; then
+ cat <<EOF
+Usage: test_smbclient_kerberos.sh USERNAME REALM PASSWORD SERVER SMBCLIENT TARGET
+EOF
+ exit 1
+fi
+
+USERNAME="$1"
+REALM=$2
+PASSWORD="$3"
+SERVER="$4"
+smbclient="$5"
+TARGET="$6"
+shift 6
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. ${incdir}/subunit.sh
+. ${incdir}/common_test_fns.inc
+
+failed=0
+
+samba_kinit=kinit
+if test -x ${BINDIR}/samba4kinit; then
+ samba_kinit=${BINDIR}/samba4kinit
+fi
+
+samba_kdestroy=kdestroy
+if test -x ${BINDIR}/samba4kdestroy; then
+ samba_kdestroy=${BINDIR}/samba4kdestroy
+fi
+
+KRB5CCNAME_PATH="${PREFIX}/ccache_smbclient_kerberos"
+KRB5CCNAME="FILE:${KRB5CCNAME_PATH}"
+export KRB5CCNAME
+
+# For ad_dc_fips this should succeed as Kerberos is set to required by default
+test_smbclient "smbclient.smb3.kerberos[//${SERVER}/tmp]" \
+ "ls; quit" //${SERVER}/tmp \
+ -U${USERNAME}%${PASSWORD} -mSMB3 ||
+ failed=$(expr $failed + 1)
+
+test_smbclient "smbclient.smb3.kerberos.required[//${SERVER}/tmp]" \
+ "ls; quit" //${SERVER}/tmp \
+ --use-kerberos=required -U${USERNAME}%${PASSWORD} -mSMB3 ||
+ failed=$(expr $failed + 1)
+
+test_smbclient "smbclient.smb3.kerberos.desired[//${SERVER}/tmp]" \
+ "ls; quit" //${SERVER}/tmp \
+ --use-kerberos=desired -U${USERNAME}%${PASSWORD} -mSMB3 ||
+ failed=$(expr $failed + 1)
+
+if [ "$TARGET" = "ad_dc_fips" ] || [ "$TARGET" = "ad_member_fips" ]; then
+ test_smbclient_expect_failure "smbclient.smb3.kerberos.off[//${SERVER}/tmp]" \
+ "ls; quit" //${SERVER}/tmp \
+ --use-kerberos=off -U${USERNAME}%${PASSWORD} -mSMB3 ||
+ failed=$(expr $failed + 1)
+else
+ test_smbclient "smbclient.smb3.kerberos.off[//${SERVER}/tmp]" \
+ "ls; quit" //${SERVER}/tmp \
+ --use-kerberos=off -U${USERNAME}%${PASSWORD} -mSMB3 ||
+ failed=$(expr $failed + 1)
+fi
+
+kerberos_kinit $samba_kinit ${USERNAME}@${REALM} ${PASSWORD}
+test_smbclient "smbclient.smb3.kerberos.ccache[//${SERVER}/tmp]" \
+ "ls; quit" //${SERVER}/tmp \
+ --use-krb5-ccache=${KRB5CCNAME} -mSMB3 ||
+ failed=$(expr $failed + 1)
+test_smbclient "smbclient.smb3.kerberos.desired[//${SERVER}/tmp]" \
+ "ls; quit" //${SERVER}/tmp \
+ --use-kerberos=desired -U${USERNAME}%${PASSWORD} -mSMB3 ||
+ failed=$(expr $failed + 1)
+
+$samba_kdestroy
+
+rm -rf $KRB5CCNAME_PATH
+
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_smbclient_krb5.sh b/source3/script/tests/test_smbclient_krb5.sh
new file mode 100755
index 0000000..98fa789
--- /dev/null
+++ b/source3/script/tests/test_smbclient_krb5.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+if [ $# -lt 1 ]; then
+ cat <<EOF
+Usage: test_smbclient_krb5.sh ccache smbclient3 server <smbclient args>
+EOF
+ exit 1
+fi
+
+KRB5CCNAME=$1
+export KRB5CCNAME
+SMBCLIENT3=$2
+SERVER=$3
+shift 3
+ADDARGS="$*"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+testit "smbclient" $VALGRIND $SMBCLIENT3 //$SERVER/tmp -c 'ls' --use-krb5-ccache=$KRB5CCNAME $ADDARGS || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_smbclient_large_file.sh b/source3/script/tests/test_smbclient_large_file.sh
new file mode 100755
index 0000000..80816be
--- /dev/null
+++ b/source3/script/tests/test_smbclient_large_file.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+if [ $# -lt 1 ]; then
+ cat <<EOF
+Usage: test_smbclient_large_file.sh ccache smbclient3 server prefix <smbclient args>
+EOF
+ exit 1
+fi
+
+KRB5CCNAME=$1
+export KRB5CCNAME
+SMBCLIENT3=$2
+SERVER=$3
+PREFIX=$4
+shift 4
+ADDARGS="$*"
+
+# Test that a noninteractive smbclient does not prompt
+test_large_write_read()
+{
+
+ cat >$PREFIX/largefile-script <<EOF
+posix
+put $PREFIX/largefile largefile
+get largefile $PREFIX/largefile2
+rm largefile
+quit
+EOF
+
+ cmd='$SMBCLIENT3 //$SERVER/xcopy_share $ADDARGS < $PREFIX/largefile-script 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+
+ if [ $? != 0 ]; then
+ echo "$out"
+ echo "command failed"
+ false
+ return
+ fi
+
+ echo "$out" | grep "getting file" >/dev/null 2>&1
+
+ if [ $? = 0 ]; then
+ true
+ else
+ echo did not get success message
+ false
+ fi
+}
+
+rm -f $PREFIX/largefile
+dd if=/dev/zero of=$PREFIX/largefile seek=$((20 * 1024 * 1024)) count=1 bs=1
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+testit "smbclient large posix write read" test_large_write_read || failed=$(expr $failed + 1)
+
+testit "cmp of read and written files" cmp $PREFIX/largefile $PREFIX/largefile2 || failed=$(expr $failed + 1)
+rm -f $PREFIX/largefile2
+
+testok $0 $failed
diff --git a/source3/script/tests/test_smbclient_list_servers.sh b/source3/script/tests/test_smbclient_list_servers.sh
new file mode 100755
index 0000000..237e82f
--- /dev/null
+++ b/source3/script/tests/test_smbclient_list_servers.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+#
+# Ensure we don't get an error smb1cli_req_writev_submit: called for dialect[SMB3_11]
+# when listing servers via -L.
+# BUG: https://bugzilla.samba.org/show_bug.cgi?id=14939
+
+if [ $# -lt 5 ]; then
+ cat <<EOF
+Usage: test_smbclient_list_servers.sh SERVER SERVER_IP USERNAME PASSWORD SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+SERVER_IP="$2"
+USERNAME="$3"
+PASSWORD="$4"
+SMBCLIENT="$5"
+shift 5
+ADDARGS="$@"
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir/subunit.sh"
+
+failed=0
+
+test_smbclient_list_servers()
+{
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -L //$SERVER -U$USERNAME%$PASSWORD -I $SERVER_IP -p139 "$ADDARGS" </dev/null 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+
+ echo "$out" | grep 'smb1cli_req_writev_submit:'
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "$out"
+ echo 'failed - should not get: smb1cli_req_writev_submit: error.'
+ return 1
+ fi
+
+ return 0
+}
+
+testit "smb1_list_servers" test_smbclient_list_servers || failed=$((failed + 1))
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_smbclient_log_basename.sh b/source3/script/tests/test_smbclient_log_basename.sh
new file mode 100755
index 0000000..f29009f
--- /dev/null
+++ b/source3/script/tests/test_smbclient_log_basename.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+# this test checks whether smbclient can log into -l log-basename
+
+if [ $# -lt 2 ]; then
+ cat <<EOF
+Usage: test_smbclient_log_basename.sh SERVER SMBCLIENT PREFIX <smbclient arguments>
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+SMBCLIENT="$2"
+PREFIX="$3"
+shift 3
+ADDARGS="$*"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+LOG_DIR=$PREFIX/st_log_basename_dir
+
+test_smbclient_log_basename()
+{
+ rm -rf $LOG_DIR
+ mkdir $LOG_DIR
+ cmd='$VALGRIND $SMBCLIENT -l $LOG_DIR -d3 //$SERVER/IPC\$ $CONFIGURATION -U%badpassword -c quit $ADDARGS'
+ out=$(eval $cmd 2>&1)
+ grep 'Client started' $LOG_DIR/log.smbclient
+}
+
+testit "smbclient log-basename" test_smbclient_log_basename || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_smbclient_machine_auth.sh b/source3/script/tests/test_smbclient_machine_auth.sh
new file mode 100755
index 0000000..c89f848
--- /dev/null
+++ b/source3/script/tests/test_smbclient_machine_auth.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# this runs the file serving tests that are expected to pass with samba3 against shares with various options
+
+if [ $# -lt 2 ]; then
+ cat <<EOF
+Usage: test_smbclient_machine_auth.sh SERVER SMBCLIENT CONFIGURATION <smbclient arguments>
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+SMBCLIENT="$2"
+# This is used by test_smbclient()
+# shellcheck disable=2034
+CONFIGURATION="${3}"
+shift 3
+ADDARGS="$*"
+
+# This is used by test_smbclient()
+# shellcheck disable=2034
+smbclient="${VALGRIND} ${SMBCLIENT}"
+
+incdir="$(dirname "${0}")/../../../testprogs/blackbox"
+. "${incdir}/subunit.sh"
+. "${incdir}/common_test_fns.inc"
+
+failed=0
+
+test_smbclient "smbclient //${SERVER}/tmp" \
+ "quit" "//${SERVER}/tmp" --machine-pass -p 139 "${ADDARGS}" || \
+ failed=$((failed + 1))
+
+# Testing these here helps because we know the machine account isn't already
+# this user/group.
+test_smbclient "smbclient //${SERVER}/forceuser" \
+ "quit" "//${SERVER}/forceuser" --machine-pass -p 139 "${ADDARGS}" || \
+ failed=$((failed + 1))
+
+test_smbclient "smbclient //${SERVER}/forcegroup" \
+ "quit" "//${SERVER}/forcegroup" --machine-pass -p 139 "${ADDARGS}" || \
+ failed=$((failed + 1))
+
+exit ${failed}
diff --git a/source3/script/tests/test_smbclient_mget.sh b/source3/script/tests/test_smbclient_mget.sh
new file mode 100755
index 0000000..5275d50
--- /dev/null
+++ b/source3/script/tests/test_smbclient_mget.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+if [ $# -lt 6 ]; then
+ cat <<EOF
+Usage: $0 smbclient3 server share user password directory
+EOF
+ exit 1
+fi
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+SMBCLIENT3="$1"
+shift
+SERVER="$1"
+shift
+SHARE="$1"
+shift
+USERNAME="$1"
+shift
+PASSWORD="$1"
+shift
+DIRECTORY="$1"
+shift
+
+cd $SELFTEST_TMPDIR || exit 1
+
+# Can't use "testit" here -- it somehow breaks the -c command passed
+# to smbclient into two, spoiling the "mget"
+
+name="smbclient mget"
+subunit_start_test "$name"
+output=$("$SMBCLIENT3" //"$SERVER"/"$SHARE" \
+ -U"$USERNAME"%"$PASSWORD" -c "recurse;prompt;mget $DIRECTORY")
+status=$?
+if [ x$status = x0 ]; then
+ subunit_pass_test "$name"
+else
+ echo "$output" | subunit_fail_test "$name"
+fi
+
+testit "rm foo" rm "$DIRECTORY"/foo || failed=$(expr $failed + 1)
+testit "rmdir $DIRECTORY" rmdir "$DIRECTORY" || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_smbclient_netbios_aliases.sh b/source3/script/tests/test_smbclient_netbios_aliases.sh
new file mode 100755
index 0000000..e48b46b
--- /dev/null
+++ b/source3/script/tests/test_smbclient_netbios_aliases.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+if [ $# -lt 6 ]; then
+ cat <<EOF
+Usage: test_smbclient_netbios_aliases.sh smbclient3 SERVER USERNAME PASSWORD PREFIX CONFIGURATION
+EOF
+ exit 1
+fi
+
+smbclient=$1
+SERVER=$2
+USERNAME=$3
+PASSWORD=$4
+PREFIX=$5
+CONFIGURATION=$6
+shift 6
+ADDADS="$@"
+
+samba_bindir="$BINDIR"
+samba_srcdir="$SRCDIR/source4"
+samba_kinit=kinit
+if test -x ${samba_bindir}/samba4kinit; then
+ samba_kinit=${samba_bindir}/samba4kinit
+fi
+
+KRB5CCNAME_PATH="$PREFIX/test_smbclient_netbios_aliases_krb5ccache"
+rm -rf $KRB5CCNAME_PATH
+
+KRB5CCNAME="FILE:$KRB5CCNAME_PATH"
+export KRB5CCNAME
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+. $incdir/common_test_fns.inc
+
+testit "kinit" kerberos_kinit ${samba_kinit} ${USERNAME} ${PASSWORD}
+
+test_smbclient "smbclient (krb5)" "ls" "//$SERVER/tmp" --use-krb5-ccache=$KRB5CCNAME || failed=$(expr $failed + 1)
+
+rm -rf $KRB5CCNAME_PATH
+
+testok $0 $failed
diff --git a/source3/script/tests/test_smbclient_ntlm.sh b/source3/script/tests/test_smbclient_ntlm.sh
new file mode 100755
index 0000000..1e53b1e
--- /dev/null
+++ b/source3/script/tests/test_smbclient_ntlm.sh
@@ -0,0 +1,80 @@
+#!/bin/sh
+
+# this runs a smbclient based authentication tests
+
+if [ $# -lt 6 ]; then
+ cat <<EOF
+Usage: test_smbclient_ntlm.sh SERVER USERNAME PASSWORD MAPTOGUEST SMBCLIENT PROTOCOL CONFIGURATION <smbclient arguments>
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+USERNAME="$2"
+PASSWORD="$3"
+MAPTOGUEST="$4"
+SMBCLIENT="$5"
+PROTOCOL="$6"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+CONFIGURATION=${7}
+shift 7
+ADDARGS="$*"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+if [ $PROTOCOL != "SMB3" -a $PROTOCOL != "NT1" ]; then
+ cat <<EOF
+Uexpected protocol specified $PROTOCOL
+EOF
+ exit 1
+fi
+
+failed=0
+
+if [ $PROTOCOL = "NT1" ]; then
+ testit "smbclient username.password.NT1OLD" $SMBCLIENT //$SERVER/IPC\$ $CONFIGURATION -U$USERNAME%$PASSWORD -mNT1 --option=clientusespnego=no --option=clientntlmv2auth=no -c quit $ADDARGS || failed=$((failed + 1))
+ testit "smbclient username.password.NT1NEW" $SMBCLIENT //$SERVER/IPC\$ $CONFIGURATION -U$USERNAME%$PASSWORD -mNT1 -c quit $ADDARGS || failed=$((failed + 1))
+fi
+if [ $PROTOCOL = "SMB3" ]; then
+ testit "smbclient username.password.SMB3" $SMBCLIENT //$SERVER/IPC\$ $CONFIGURATION -U$USERNAME%$PASSWORD -mSMB3 -c quit $ADDARGS || failed=$((failed + 1))
+fi
+
+if [ $PROTOCOL = "NT1" ]; then
+ testit "smbclient anonymous.nopassword.NT1OLD" $SMBCLIENT //$SERVER/IPC\$ $CONFIGURATION -U% -mNT1 --option=clientusespnego=no --option=clientntlmv2auth=no -c quit $ADDARGS || failed=$((failed + 1))
+ testit "smbclient anonymous.nopassword.NT1NEW" $SMBCLIENT //$SERVER/IPC\$ $CONFIGURATION -U% -mNT1 -c quit $ADDARGS || failed=$((failed + 1))
+fi
+if [ $PROTOCOL = "SMB3" ]; then
+ testit "smbclient anonymous.nopassword.SMB3" $SMBCLIENT //$SERVER/IPC\$ $CONFIGURATION -U% -mSMB3 -c quit $ADDARGS || failed=$((failed + 1))
+fi
+if test x"${MAPTOGUEST}" = x"never"; then
+ if [ $PROTOCOL = "NT1" ]; then
+ testit_expect_failure "smbclient anonymous.badpassword.NT1NEW.fail" $SMBCLIENT //$SERVER/IPC\$ $CONFIGURATION -U%badpassword -mNT1 -c quit $ADDARGS || failed=$((failed + 1))
+ fi
+ if [ $PROTOCOL = "SMB3" ]; then
+ testit_expect_failure "smbclient anonymous.badpassword.SMB3.fail" $SMBCLIENT //$SERVER/IPC\$ $CONFIGURATION -U%badpassword -mSMB3 -c quit $ADDARGS || failed=$((failed + 1))
+ fi
+else
+ if [ $PROTOCOL = "NT1" ]; then
+ testit "smbclient anonymous.badpassword.NT1NEW.guest" $SMBCLIENT //$SERVER/IPC\$ $CONFIGURATION -U%badpassword -mNT1 -c quit $ADDARGS || failed=$((failed + 1))
+ fi
+ if [ $PROTOCOL = "SMB3" ]; then
+ testit "smbclient anonymous.badpassword.SMB3.guest" $SMBCLIENT //$SERVER/IPC\$ $CONFIGURATION -U%badpassword -mSMB3 -c quit $ADDARGS || failed=$((failed + 1))
+ fi
+
+ if [ $PROTOCOL = "NT1" ]; then
+ testit "smbclient baduser.badpassword.NT1NEW.guest" $SMBCLIENT //$SERVER/IPC\$ $CONFIGURATION -Ubaduser%badpassword -mNT1 -c quit $ADDARGS || failed=$((failed + 1))
+ fi
+ if [ $PROTOCOL = "SMB3" ]; then
+ testit "smbclient baduser.badpassword.SMB3.guest" $SMBCLIENT //$SERVER/IPC\$ $CONFIGURATION -Ubaduser%badpassword -mSMB3 -c quit $ADDARGS || failed=$((failed + 1))
+ fi
+ if [ $PROTOCOL = "NT1" ]; then
+ testit_expect_failure "smbclient baduser.badpassword.NT1OLD.signfail" $SMBCLIENT //$SERVER/IPC\$ $CONFIGURATION -Ubaduser%badpassword -mNT1 --option=clientusespnego=no --option=clientntlmv2auth=no --client-protection=sign -c quit $ADDARGS || failed=$((failed + 1))
+ testit_expect_failure "smbclient baduser.badpassword.NT1NEW.signfail" $SMBCLIENT //$SERVER/IPC\$ $CONFIGURATION -Ubaduser%badpassword -mNT1 --client-protection=sign -c quit $ADDARGS || failed=$((failed + 1))
+ fi
+ if [ $PROTOCOL = "SMB3" ]; then
+ testit_expect_failure "smbclient baduser.badpassword.SMB3.signfail" $SMBCLIENT //$SERVER/IPC\$ $CONFIGURATION -Ubaduser%badpassword -mSMB3 --client-protection=sign -c quit $ADDARGS || failed=$((failed + 1))
+ fi
+fi
+
+exit ${failed}
diff --git a/source3/script/tests/test_smbclient_s3.sh b/source3/script/tests/test_smbclient_s3.sh
new file mode 100755
index 0000000..cbff502
--- /dev/null
+++ b/source3/script/tests/test_smbclient_s3.sh
@@ -0,0 +1,2364 @@
+#!/bin/sh
+
+# this runs the file serving tests that are expected to pass with samba3
+
+if [ $# -lt 13 ]; then
+ cat <<EOF
+Usage: test_smbclient_s3.sh SERVER SERVER_IP DOMAIN USERNAME PASSWORD USERID LOCAL_PATH PREFIX SMBCLIENT WBINFO NET CONFIGURATION PROTOCOL
+EOF
+ exit 1
+fi
+
+SERVER="${1}"
+SERVER_IP="${2}"
+DOMAIN="${3}"
+USERNAME="${4}"
+PASSWORD="${5}"
+USERID="${6}"
+LOCAL_PATH="${7}"
+PREFIX="${8}"
+SMBCLIENT="${9}"
+WBINFO="${10}"
+NET="${11}"
+CONFIGURATION="${12}"
+PROTOCOL="${13}"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+WBINFO="$VALGRIND ${WBINFO}"
+shift 13
+RAWARGS="${CONFIGURATION} -m${PROTOCOL}"
+ADDARGS="${RAWARGS} $*"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+# Test that a noninteractive smbclient does not prompt
+test_noninteractive_no_prompt()
+{
+ prompt="smb"
+
+ cmd='echo du | $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+
+ if [ $? != 0 ]; then
+ echo "$out"
+ echo "command failed"
+ return 1
+ fi
+
+ echo "$out" | grep $prompt >/dev/null 2>&1
+
+ if [ $? = 0 ]; then
+ # got a prompt .. fail
+ echo matched interactive prompt in non-interactive mode
+ return 1
+ fi
+
+ return 0
+}
+
+# Test that an interactive smbclient prompts to stdout
+test_interactive_prompt_stdout()
+{
+ prompt="smb"
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+
+ cat >$tmpfile <<EOF
+du
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "command failed"
+ return 1
+ fi
+
+ echo "$out" | grep $prompt >/dev/null 2>&1
+
+ if [ $? != 0 ]; then
+ echo failed to match interactive prompt on stdout
+ return 1
+ fi
+
+ return 0
+}
+
+# Test creating a bad symlink and deleting it.
+test_bad_symlink()
+{
+ prompt="posix_unlink deleted file /newname"
+ tmpfile=$PREFIX/smbclient_bad_symlinks_commands
+
+ cat >$tmpfile <<EOF
+posix
+posix_unlink newname
+symlink badname newname
+posix_unlink newname
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed create then delete bad symlink with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep "$prompt" >/dev/null 2>&1
+
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed create then delete bad symlink - grep failed with $ret"
+ return 1
+ fi
+
+ return 0
+}
+
+# Test creating a good symlink and deleting it by path.
+test_good_symlink()
+{
+ tmpfile=$PREFIX/smbclient.in.$$
+ slink_name="$LOCAL_PATH/slink"
+ slink_target="$LOCAL_PATH/slink_target"
+
+ touch $slink_target
+ ln -s $slink_target $slink_name
+ cat >$tmpfile <<EOF
+del slink
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed delete good symlink with error $ret"
+ rm $slink_target
+ rm $slink_name
+ return 1
+ fi
+
+ if [ ! -e $slink_target ]; then
+ echo "failed delete good symlink - symlink target deleted !"
+ rm $slink_target
+ rm $slink_name
+ return 1
+ fi
+
+ if [ -e $slink_name ]; then
+ echo "failed delete good symlink - symlink still exists"
+ rm $slink_target
+ rm $slink_name
+ return 1
+ fi
+
+ rm $slink_target
+ return 0
+}
+
+# Test writing into a read-only directory (logon as guest) fails.
+test_read_only_dir()
+{
+ prompt="NT_STATUS_ACCESS_DENIED making remote directory"
+ tmpfile=$PREFIX/smbclient.in.$$
+
+ ##
+ ## We can't do this as non-root. We always have rights to
+ ## create the directory.
+ ##
+ if [ "$USERID" != 0 ]; then
+ echo "skipping test_read_only_dir as non-root"
+ return 0
+ fi
+
+ ##
+ ## We can't do this with an encrypted connection. No credentials
+ ## to set up the channel.
+ ##
+ if [ "$ADDARGS" = "-e" ]; then
+ echo "skipping test_read_only_dir with encrypted connection"
+ return 0
+ fi
+
+ cat >$tmpfile <<EOF
+mkdir a_test_dir
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U% "//$SERVER/$1" -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed writing into read-only directory with error $ret"
+
+ return 1
+ fi
+
+ echo "$out" | grep "$prompt" >/dev/null 2>&1
+
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed writing into read-only directory - grep failed with $ret"
+ return 1
+ fi
+
+ return 0
+}
+
+# Test sending a message
+test_message()
+{
+ tmpfile=$PREFIX/message_in.$$
+
+ cat >$tmpfile <<EOF
+Test message from pid $$
+EOF
+
+ cmd='$SMBCLIENT "$@" -U$USERNAME%$PASSWORD -M $SERVER -p 139 $ADDARGS -n msgtest < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed sending message to $SERVER with error $ret"
+ rm -f $tmpfile
+ return 1
+ fi
+
+ # The server writes this into a file message.msgtest, via message.%m to test the % sub code
+ cmd='$SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmpguest -p 139 $ADDARGS -c "get message.msgtest $PREFIX/message_out.$$" 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed getting sent message from $SERVER with error $ret"
+ return 1
+ fi
+
+ if cmp $PREFIX/message_out.$$ $tmpfile; then
+ echo "failed comparison of message from $SERVER"
+ return 1
+ fi
+
+ return 0
+}
+
+# Test reading an owner-only file (logon as guest) fails.
+test_owner_only_file()
+{
+ prompt="NT_STATUS_ACCESS_DENIED opening remote file"
+ tmpfile=$PREFIX/smbclient.in.$$
+
+ ##
+ ## We can't do this as non-root. We always have rights to
+ ## read the file.
+ ##
+ if [ "$USERID" != 0 ]; then
+ echo "skipping test_owner_only_file as non-root"
+ return 0
+ fi
+
+ ##
+ ## We can't do this with an encrypted connection. No credentials
+ ## to set up the channel.
+ ##
+ if [ "$ADDARGS" = "-e" ]; then
+ echo "skipping test_owner_only_file with encrypted connection"
+ return 0
+ fi
+
+ cat >$tmpfile <<EOF
+get unreadable_file
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U% //$SERVER/ro-tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed reading owner-only file with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep "$prompt" >/dev/null 2>&1
+
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed reading owner-only file - grep failed with $ret"
+ return 1
+ fi
+
+ return 0
+}
+
+# Test accessing an msdfs path.
+test_msdfs_link()
+{
+ tmpfile=$PREFIX/smbclient.in.$$
+ prompt=" msdfs-target "
+
+ cmd='$SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/msdfs-share -I $SERVER_IP $ADDARGS -m $PROTOCOL -c dir 2>&1'
+ out=$(eval $cmd)
+ ret=$?
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed listing msfds-share\ with error $ret"
+ return 1
+ fi
+
+ cat >$tmpfile <<EOF
+ls
+cd \\msdfs-src1
+ls msdfs-target
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/msdfs-share -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed accessing \\msdfs-src1 link with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep "$prompt" >/dev/null 2>&1
+
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed listing \\msdfs-src1 - grep failed with $ret"
+ return 1
+ fi
+
+ cat >$tmpfile <<EOF
+ls
+cd \\deeppath\\msdfs-src2
+ls msdfs-target
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/msdfs-share -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed accessing \\deeppath\\msdfs-src2 link with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep "$prompt" >/dev/null 2>&1
+
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed listing \\deeppath\\msdfs-src2 - grep failed with $ret"
+ return 1
+ fi
+
+ return 0
+}
+
+# Test recursive listing across msdfs links
+test_msdfs_recursive_dir()
+{
+ tmpfile=$PREFIX/smbclient.in.$$
+
+ cat >$tmpfile <<EOF
+recurse
+dir
+quit
+EOF
+
+ cmd='$SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/msdfs-share -I $SERVER_IP $ADDARGS -m $PROTOCOL < $tmpfile 2>&1'
+ out=$(eval $cmd)
+ ret="$?"
+
+ if [ "$ret" -ne 0 ]; then
+ echo "$out"
+ echo "failed listing msfds-share\ with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep 'NT_STATUS_OBJECT_PATH_NOT_FOUND listing \widelinks\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\dot\*' > /dev/null 2>&1
+
+ ret="$?"
+ if [ "$ret" -ne 0 ]; then
+ echo "$out"
+ echo "Listing \\msdfs-share recursively did not properly end in symlink recursion"
+ fi
+
+ return 0
+}
+
+# Test doing a normal file rename on an msdfs path.
+test_msdfs_rename()
+{
+ tmpfile="$PREFIX/smbclient.in.$$"
+ filename_src="src.$$"
+ filename_dst="dest.$$"
+ filename_src_path="$PREFIX/$filename_src"
+ rm -f "$filename_src_path"
+ touch "$filename_src_path"
+
+ #
+ # Use both non-force and force rename to
+ # ensure we test both codepaths inside libsmb.
+ #
+ cat >$tmpfile <<EOF
+lcd $PREFIX
+put $filename_src
+ren $filename_src $filename_dst -f
+ren $filename_dst $filename_src
+del $filename_src
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/msdfs-share -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f "$tmpfile"
+ rm -f "$filename_src_path"
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed renaming $filename_src $filename_dst with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep "NT_STATUS" >/dev/null 2>&1
+
+ ret="$?"
+ if [ "$ret" -eq 0 ]; then
+ echo "$out"
+ echo "renaming $filename_src $filename_dst got NT_STATUS_ error"
+ return 1
+ fi
+ return 0
+}
+
+# Test doing a normal file hardlink on an msdfs path.
+test_msdfs_hardlink()
+{
+ tmpfile="$PREFIX/smbclient.in.$$"
+ filename_src="src.$$"
+ filename_dst="dest.$$"
+ filename_src_path="$PREFIX/$filename_src"
+ rm -f "$filename_src_path"
+ touch "$filename_src_path"
+
+ cat >$tmpfile <<EOF
+lcd $PREFIX
+put $filename_src
+hardlink $filename_src $filename_dst
+del $filename_src
+del $filename_dst
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/msdfs-share -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f "$tmpfile"
+ rm -f "$filename_src_path"
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed hardlink $filename_src $filename_dst with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep "NT_STATUS" >/dev/null 2>&1
+
+ ret="$?"
+ if [ "$ret" -eq 0 ]; then
+ echo "$out"
+ echo "hardlink $filename_src $filename_dst got NT_STATUS_ error"
+ return 1
+ fi
+ return 0
+}
+
+test_msdfs_del()
+{
+ tmpfile="$PREFIX/smbclient.in.$$"
+ filename_src="src.$$"
+ filename_src_path="$PREFIX/$filename_src"
+ rm -f "$filename_src_path"
+ touch "$filename_src_path"
+
+ cat > $tmpfile <<EOF
+lcd $PREFIX
+cd dfshop1
+cd dfshop2
+put $filename_src
+del $filename_src
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/msdfs-share -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=`eval $cmd`
+ ret=$?
+ rm -f "$tmpfile"
+ rm -f "$filename_src_path"
+
+ if [ $ret != 0 ] ; then
+ echo "$out"
+ echo "failed deleting $filename_src with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep "NT_STATUS" >/dev/null 2>&1
+
+ ret="$?"
+ if [ "$ret" -eq 0 ] ; then
+ echo "$out"
+ echo "del $filename_src NT_STATUS_ error"
+ return 1
+ fi
+ return 0
+}
+
+test_msdfs_deltree()
+{
+ tmpfile="$PREFIX/smbclient.in.$$"
+ dirname_src="foodir.$$"
+ filename_src="src.$$"
+ filename_src_path="$PREFIX/$filename_src"
+ dirname_src_path="$PREFIX/$dirname"
+ rm -f "$filename_src_path"
+ touch "$filename_src_path"
+
+ cat > $tmpfile <<EOF
+lcd $PREFIX
+cd dfshop1
+cd dfshop2
+mkdir $dirname_src
+cd $dirname_src
+put $filename_src
+cd ..
+deltree $dirname_src
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/msdfs-share -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=`eval $cmd`
+ ret=$?
+ rm -f "$tmpfile"
+ rm -f "$filename_src_path"
+ rm -f "$dirname_src_path"
+
+ if [ $ret != 0 ] ; then
+ echo "$out"
+ echo "deltree failed deleting dir $dirname_src with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep "NT_STATUS" >/dev/null 2>&1
+
+ ret="$?"
+ if [ "$ret" -eq 0 ] ; then
+ echo "$out"
+ echo "deltree $dirname_src NT_STATUS_ error"
+ return 1
+ fi
+ return 0
+}
+
+# Archive bits are correctly set on file/dir creation and rename.
+test_rename_archive_bit()
+{
+ prompt_file="attributes: A (20)"
+ prompt_dir="attributes: D (10)"
+ tmpfile="$PREFIX/smbclient.in.$$"
+ filename="foo.$$"
+ filename_ren="bar.$$"
+ dirname="foodir.$$"
+ dirname_ren="bardir.$$"
+ filename_path="$PREFIX/$filename"
+ local_name1="$LOCAL_PATH/$filename"
+ local_name2="$LOCAL_PATH/$filename_ren"
+ local_dir_name1="$LOCAL_PATH/$dirname"
+ local_dir_name2="$LOCAL_PATH/$dirname_ren"
+
+ rm -f $filename_path
+ rm -f $local_name1
+ rm -f $local_name2
+
+ # Create a new file, ensure it has 'A' attributes.
+ touch $filename_path
+
+ cat >$tmpfile <<EOF
+lcd $PREFIX
+put $filename
+allinfo $filename
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed creating file $filename with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep "$prompt_file" >/dev/null 2>&1
+
+ ret=$?
+
+ rm -f $filename_path
+ rm -f $local_name1
+ rm -f $local_name2
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "Attributes incorrect on new file $ret"
+ return 1
+ fi
+
+ # Now check if we remove 'A' and rename, the A comes back.
+ touch $filename_path
+
+ cat >$tmpfile <<EOF
+lcd $PREFIX
+put $filename
+setmode $filename -a
+ren $filename $filename_ren
+allinfo $filename_ren
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed creating file and renaming $filename with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep "$prompt_file" >/dev/null 2>&1
+
+ ret=$?
+
+ rm -f $filename_path
+ rm -f $local_name1
+ rm -f $local_name2
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "Attributes incorrect on renamed file $ret"
+ return 1
+ fi
+
+ rm -rf $local_dir_name1
+ rm -rf $local_dir_name2
+
+ # Create a new directory, ensure it has 'D' but not 'A' attributes.
+
+ cat >$tmpfile <<EOF
+mkdir $dirname
+allinfo $dirname
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed creating directory $dirname with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep "$prompt_dir" >/dev/null 2>&1
+
+ ret=$?
+
+ rm -rf $local_dir_name1
+ rm -rf $local_dir_name2
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "Attributes incorrect on new directory $ret"
+ return 1
+ fi
+
+ # Now check if we rename, we still only have 'D' attributes
+
+ cat >$tmpfile <<EOF
+mkdir $dirname
+ren $dirname $dirname_ren
+allinfo $dirname_ren
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed creating directory $dirname and renaming with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep "$prompt_dir" >/dev/null 2>&1
+
+ ret=$?
+
+ rm -f $local_name1
+ rm -f $local_name2
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "Attributes incorrect on renamed directory $ret"
+ return 1
+ fi
+
+ return 0
+}
+
+# Test authenticating using the winbind ccache
+test_ccache_access()
+{
+ $WBINFO --ccache-save="${USERNAME}%${PASSWORD}"
+ ret=$?
+
+ if [ $ret != 0 ]; then
+ echo "wbinfo failed to store creds in cache (user='${USERNAME}', pass='${PASSWORD}')"
+ return 1
+ fi
+
+ $SMBCLIENT //$SERVER_IP/tmp --use-winbind-ccache -U "${USERNAME}" $ADDARGS -c quit 2>&1
+ ret=$?
+
+ if [ $ret != 0 ]; then
+ echo "smbclient failed to use cached credentials"
+ return 1
+ fi
+
+ $WBINFO --ccache-save="${USERNAME}%GarBage"
+ ret=$?
+
+ if [ $ret != 0 ]; then
+ echo "wbinfo failed to store creds in cache (user='${USERNAME}', pass='GarBage')"
+ return 1
+ fi
+
+ $SMBCLIENT //$SERVER_IP/tmp --use-winbind-ccache -U "${USERNAME}" $ADDARGS -c quit 2>&1
+ ret=$?
+
+ if [ $ret -eq 0 ]; then
+ echo "smbclient succeeded with wrong cached credentials"
+ return 1
+ fi
+
+ $WBINFO --logoff
+}
+
+# Test authenticating using the winbind ccache
+test_auth_file()
+{
+ tmpfile=$PREFIX/smbclient.in.$$
+ cat >$tmpfile <<EOF
+username=${USERNAME}
+password=${PASSWORD}
+domain=${DOMAIN}
+EOF
+ $SMBCLIENT //$SERVER_IP/tmp --authentication-file=$tmpfile $ADDARGS -c quit 2>&1
+ ret=$?
+ rm $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "smbclient failed to use auth file"
+ return 1
+ fi
+
+ cat >$tmpfile <<EOF
+username=${USERNAME}
+password=xxxx
+domain=${DOMAIN}
+EOF
+ $SMBCLIENT //$SERVER_IP/tmp --authentication-file=$tmpfile $ADDARGS -c quit 2>&1
+ ret=$?
+ rm $tmpfile
+
+ if [ $ret -eq 0 ]; then
+ echo "smbclient succeeded with wrong auth file credentials"
+ return 1
+ fi
+}
+
+# Test doing a directory listing with backup privilege.
+test_backup_privilege_list()
+{
+ tmpfile=$PREFIX/smbclient_backup_privilege_list
+
+ # selftest uses the forward slash as a separator, but "net sam rights
+ # grant" requires the backslash separator
+ USER_TMP=$(printf '%s' "$USERNAME" | tr '/' '\\')
+
+ # If we don't have a DOMAIN component to the username, add it.
+ printf '%s' "$USER_TMP" | grep '\\' 2>&1
+ ret=$?
+ if [ $ret != 0 ]; then
+ priv_username="$DOMAIN\\$USER_TMP"
+ else
+ priv_username="$USER_TMP"
+ fi
+
+ $NET sam rights grant $priv_username SeBackupPrivilege 2>&1
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "Failed to add SeBackupPrivilege to user $priv_username - $ret"
+ return 1
+ fi
+
+ cat >$tmpfile <<EOF
+backup
+ls
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed backup privilege list $ret"
+ return 1
+ fi
+
+ # Now remove all privileges from this SID.
+ $NET sam rights revoke $priv_username SeBackupPrivilege 2>&1
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "failed to remove SeBackupPrivilege from user $priv_username - $ret"
+ return 1
+ fi
+}
+
+# Test accessing an share with bad names (won't convert).
+test_bad_names()
+{
+ # First with SMB1
+
+ if [ $PROTOCOL = "NT1" ]; then
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/badname-tmp -I $SERVER_IP $ADDARGS -m$PROTOCOL -c ls 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed accessing badname-tmp (SMB1) with error $ret"
+ return 1
+ fi
+
+ echo "$out" | wc -l 2>&1 | grep 5
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed listing \\badname-tmp - grep of number of lines (1) failed with $ret"
+ return 1
+ fi
+
+ echo "$out" | grep '^ \. *D'
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed listing \\badname-tmp - grep (1) failed with $ret"
+ return 1
+ fi
+
+ echo "$out" | grep '^ \.\. *D'
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed listing \\badname-tmp - grep (2) failed with $ret"
+ return 1
+ fi
+
+ echo "$out" | grep '^ blank.txt *N'
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed listing \\badname-tmp - grep (3) failed with $ret"
+ return 1
+ fi
+
+ echo "$out" | grep '^ *$'
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed listing \\badname-tmp - grep (4) failed with $ret"
+ return 1
+ fi
+
+ echo "$out" | grep 'blocks of size.*blocks available'
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed listing \\badname-tmp - grep (5) failed with $ret"
+ return 1
+ fi
+ fi
+
+ if [ $PROTOCOL = "SMB3" ]; then
+
+ # Now check again with -mSMB3
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/badname-tmp -I $SERVER_IP $ADDARGS -m$PROTOCOL -c ls 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed accessing badname-tmp (SMB3) with error $ret"
+ return 1
+ fi
+
+ echo "$out" | wc -l 2>&1 | grep 5
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed listing \\badname-tmp - SMB3 grep of number of lines (1) failed with $ret"
+ return 1
+ fi
+
+ echo "$out" | grep '^ \. *D'
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed listing \\badname-tmp - SMB3 grep (1) failed with $ret"
+ return 1
+ fi
+
+ echo "$out" | grep '^ \.\. *D'
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed listing \\badname-tmp - SMB3 grep (2) failed with $ret"
+ return 1
+ fi
+
+ echo "$out" | grep '^ blank.txt *N'
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed listing \\badname-tmp - SMB3 grep (3) failed with $ret"
+ return 1
+ fi
+
+ echo "$out" | grep '^ *$'
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed listing \\badname-tmp - SMB3 grep (4) failed with $ret"
+ return 1
+ fi
+
+ echo "$out" | grep 'blocks of size.*blocks available'
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed listing \\badname-tmp - SMB3 grep (5) failed with $ret"
+ return 1
+ fi
+ fi
+}
+
+# Test accessing an share with a name that must be mangled - with acl_xattrs.
+# We know foo:bar gets mangled to FF4GBY~Q with the default name-mangling algorithm (hash2).
+test_mangled_names()
+{
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ cat >$tmpfile <<EOF
+ls
+cd FF4GBY~Q
+ls
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/manglenames_share -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed accessing manglenames_share with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep 'NT_STATUS'
+ ret=$?
+ if [ $ret = 0 ]; then
+ echo "$out"
+ echo "failed - NT_STATUS_XXXX listing \\manglenames_share\\FF4GBY~Q"
+ return 1
+ fi
+}
+
+# Test using scopy to copy a file on the server.
+test_scopy()
+{
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ scopy_file=$PREFIX/scopy_file
+
+ rm -f $scopy_file
+ cat >$tmpfile <<EOF
+put ${SMBCLIENT}
+scopy smbclient scopy_file
+lcd ${PREFIX}
+get scopy_file
+del smbclient
+del scopy_file
+quit
+EOF
+ if [ $PROTOCOL = "SMB3" ]; then
+ # First SMB3
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS -m$PROTOOCL < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ out1=$(md5sum ${SMBCLIENT} | sed -e 's/ .*//')
+ out2=$(md5sum ${scopy_file} | sed -e 's/ .*//')
+ rm -f $tmpfile
+ rm -f $scopy_file
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed scopy test (1) with output $ret"
+ return 1
+ fi
+
+ if [ $out1 != $out2 ]; then
+ echo "$out1 $out2"
+ echo "failed md5sum (1)"
+ return 1
+ fi
+ fi
+ #
+ # Now do again using SMB1
+ # to force client-side fallback.
+ #
+
+ if [ $PROTOCOL = "NT1" ]; then
+ cat >$tmpfile <<EOF
+put ${SMBCLIENT}
+scopy smbclient scopy_file
+lcd ${PREFIX}
+get scopy_file
+del smbclient
+del scopy_file
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS -m$PROTOCOL < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ out1=$(md5sum ${SMBCLIENT} | sed -e 's/ .*//')
+ out2=$(md5sum ${scopy_file} | sed -e 's/ .*//')
+ rm -f $tmpfile
+ rm -f $scopy_file
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed scopy test (2) with output $ret"
+ return 1
+ fi
+
+ if [ $out1 != $out2 ]; then
+ echo "$out1 $out2"
+ echo "failed md5sum (2)"
+ return 1
+ fi
+ fi
+}
+
+# Test creating a stream on the root of the share directory filename - :foobar
+test_toplevel_stream()
+{
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ cat >$tmpfile <<EOF
+put ${PREFIX}/smbclient_interactive_prompt_commands :foobar
+allinfo \\
+setmode \\ -a
+quit
+EOF
+ # Only with SMB3???
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS -mSMB3 < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed creating toplevel stream :foobar with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep '^stream:.*:foobar'
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed creating toplevel stream :foobar"
+ return 1
+ fi
+}
+
+# Test wide links are restricted.
+test_widelinks()
+{
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ cat >$tmpfile <<EOF
+cd dot
+ls
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/widelinks_share -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed accessing widelinks_share with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep 'NT_STATUS'
+ ret=$?
+ if [ $ret = 0 ]; then
+ echo "$out"
+ echo "failed - NT_STATUS_XXXX listing \\widelinks_share\\dot"
+ return 1
+ fi
+
+ cat >$tmpfile <<EOF
+allinfo source
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/widelinks_share -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed accessing widelinks_share with error $ret"
+ return 1
+ fi
+
+ # This should fail with NT_STATUS_OBJECT_NAME_NOT_FOUND
+ echo "$out" | grep 'NT_STATUS_OBJECT_NAME_NOT_FOUND'
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed - should get NT_STATUS_OBJECT_NAME_NOT_FOUND listing \\widelinks_share\\source"
+ return 1
+ fi
+}
+
+# Test creating then deleting a stream file doesn't leave a lost-XXXXX directory.
+test_streams_depot_delete()
+{
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ rm -rf "$LOCAL_PATH/lost-*"
+
+ cat >$tmpfile <<EOF
+put ${PREFIX}/smbclient_interactive_prompt_commands foo:bar
+del foo
+ls lost*
+quit
+EOF
+ # This only works with SMB3?
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS -mSMB3 < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed creating then deleting foo:bar with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep 'NT_STATUS_NO_SUCH_FILE listing \\lost\*'
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "deleting foo:bar left lost-XXX directory"
+ rm -rf "$LOCAL_PATH/lost-*"
+ return 1
+ fi
+}
+
+# Test follow symlinks can't access symlinks
+test_nosymlinks()
+{
+ # Setup test dirs.
+ local_test_dir="$LOCAL_PATH/nosymlinks/test"
+ local_slink_name="$local_test_dir/source"
+ local_slink_target="$local_test_dir/nosymlink_target_file"
+
+ share_test_dir="test"
+ share_foo_dir="$share_test_dir/foo"
+ share_foobar_dir="$share_test_dir/foo/bar"
+ share_target_file="$share_test_dir/foo/bar/testfile"
+
+ rm -rf $local_test_dir
+
+ local_nosymlink_target_file="nosymlink_target_file"
+ echo "$local_slink_target" >$PREFIX/$local_nosymlink_target_file
+
+ local_foobar_target_file="testfile"
+ echo "$share_target_file" >$PREFIX/$local_foobar_target_file
+
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ cat >$tmpfile <<EOF
+mkdir $share_test_dir
+mkdir $share_foo_dir
+mkdir $share_foobar_dir
+lcd $PREFIX
+cd /$share_test_dir
+put $local_nosymlink_target_file
+cd /$share_foobar_dir
+put $local_foobar_target_file
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/nosymlinks -I $SERVER_IP $LOCAL_ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+ rm -f $PREFIX/$local_nosymlink_target_file
+ rm -f $PREFIX/$local_foobar_target_file
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "failed accessing local_symlinks with error $ret"
+ false
+ return
+ fi
+
+ echo "$out" | grep 'NT_STATUS_'
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "$out"
+ echo "failed - got an NT_STATUS error"
+ false
+ return
+ fi
+
+ # Create the symlink locally
+ ln -s $local_slink_target $local_slink_name
+
+ # Getting a file through a symlink name should fail.
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ cat >$tmpfile <<EOF
+get test\\source
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/nosymlinks -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "failed accessing nosymlinks with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep 'NT_STATUS_OBJECT_NAME_NOT_FOUND'
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "failed - should get NT_STATUS_OBJECT_NAME_NOT_FOUND getting \\nosymlinks\\source"
+ return 1
+ fi
+
+ # But we should be able to create and delete directories.
+ cat >$tmpfile <<EOF
+mkdir test\\a
+mkdir test\\a\\b
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/nosymlinks -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "failed accessing nosymlinks with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep 'NT_STATUS'
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "$out"
+ echo "failed - NT_STATUS_XXXX doing mkdir a; mkdir a\\b on \\nosymlinks"
+ return 1
+ fi
+
+ # Ensure regular file/directory access also works.
+ cat >$tmpfile <<EOF
+cd test\\foo\\bar
+ls
+get testfile -
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/nosymlinks -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "failed accessing nosymlinks with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep 'NT_STATUS'
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "$out"
+ echo "failed - NT_STATUS_XXXX doing cd foo\\bar; get testfile on \\nosymlinks"
+ return 1
+ fi
+
+ # CLEANUP
+ rm -f $local_slink_name
+
+ cat >$tmpfile <<EOF
+deltree test
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/nosymlinks -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "failed accessing nosymlinks with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep 'NT_STATUS'
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "$out"
+ echo "failed - NT_STATUS_XXXX doing cd foo\\bar; get testfile on \\nosymlinks"
+ return 1
+ fi
+}
+
+# Test we can follow normal symlinks.
+# Bug: https://bugzilla.samba.org/show_bug.cgi?id=12860
+# Note - this needs to be tested over SMB3, not SMB1.
+
+test_local_symlinks()
+{
+ # Setup test dirs.
+ LOCAL_RAWARGS="${CONFIGURATION} -mSMB3"
+ LOCAL_ADDARGS="${LOCAL_RAWARGS} $*"
+
+ share_test_dir="test"
+ share_slink_target_dir="$share_test_dir/dir1"
+
+ local_test_dir="$LOCAL_PATH/local_symlinks/$share_test_dir"
+ local_slink_name="$local_test_dir/sym_name"
+ local_slink_target_dir="$local_test_dir/dir1"
+
+ rm -rf $local_test_dir
+
+ # Create the initial directories
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ cat >$tmpfile <<EOF
+mkdir $share_test_dir
+mkdir $share_slink_target_dir
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/local_symlinks -I $SERVER_IP $LOCAL_ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "failed accessing local_symlinks with error $ret"
+ false
+ return
+ fi
+
+ echo "$out" | grep 'NT_STATUS_'
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "$out"
+ echo "failed - got an NT_STATUS error"
+ false
+ return
+ fi
+
+ # Create the symlink locally
+ ln -s $local_slink_target_dir $local_slink_name
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "failed - unable to create symlink"
+ ls -la $local_test_dir
+ false
+ return
+ fi
+
+ # Can we cd into the symlink name and ls ?
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ cat >$tmpfile <<EOF
+cd $share_test_dir\\sym_name
+ls
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/local_symlinks -I $SERVER_IP $LOCAL_ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "failed accessing local_symlinks with error $ret"
+ false
+ return
+ fi
+
+ echo "$out" | grep 'NT_STATUS_'
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "$out"
+ echo "failed - got an NT_STATUS error"
+ false
+ return
+ fi
+
+ # CLEANUP
+ rm -f $local_slink_name
+
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ cat >$tmpfile <<EOF
+deltree $share_test_dir
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/local_symlinks -I $SERVER_IP $LOCAL_ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "failed accessing local_symlinks with error $ret"
+ false
+ return
+ fi
+
+ echo "$out" | grep 'NT_STATUS_'
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "$out"
+ echo "failed - got an NT_STATUS error"
+ false
+ return
+ fi
+}
+
+#
+# Regression test for CVE-2019-10197
+# we should always get ACCESS_DENIED
+#
+test_noperm_share_regression()
+{
+ cmd='$SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/noperm -I $SERVER_IP $LOCAL_ADDARGS -c "ls;ls" 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "$out"
+ echo "failed accessing no perm share should not work"
+ return 1
+ fi
+
+ num=$(echo "$out" | grep 'NT_STATUS_ACCESS_DENIED' | wc -l)
+ if [ "$num" -ne "2" ]; then
+ echo "$out"
+ echo "failed num[$num] - two NT_STATUS_ACCESS_DENIED lines expected"
+ return 1
+ fi
+
+ return 0
+}
+
+# Test smbclient deltree command
+test_deltree()
+{
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ deltree_dir=$PREFIX/deltree_dir
+
+ rm -rf $deltree_dir
+ cat >$tmpfile <<EOF
+mkdir deltree_dir
+mkdir deltree_dir/foo
+mkdir deltree_dir/foo/bar
+put ${SMBCLIENT} deltree_dir/foo/bar/client
+deltree deltree_dir
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed deltree test with output $ret"
+ false
+ return
+ fi
+
+ echo "$out" | grep 'NT_STATUS_'
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "$out"
+ echo "failed - got an NT_STATUS error"
+ false
+ return
+ fi
+
+ if [ -d $deltree_dir ]; then
+ echo "deltree did not delete everything"
+ false
+ return
+ fi
+}
+
+# Test smbclient setmode command
+test_setmode()
+{
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+
+ cat >$tmpfile <<EOF
+del test_setmode
+put ${SMBCLIENT} test_setmode
+setmode test_setmode +r +s +h +a
+allinfo test_setmode
+setmode test_setmode -rsha
+allinfo test_setmode
+del test_setmode
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed setmode test with output $ret"
+ false
+ return
+ fi
+
+ echo "$out" | grep 'attributes: RHSA'
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "failed - should get attributes: RHSA"
+ false
+ return
+ fi
+
+ echo "$out" | grep 'attributes: (80)'
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "failed - should also get attributes: (80)"
+ false
+ return
+ fi
+}
+
+# Test smbclient utimes command
+test_utimes()
+{
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+
+ saved_TZ="$TZ"
+ TZ=UTC
+ export TZ
+ saved_LANG="$LANG"
+ LANG=C
+ export LANG
+
+ cat >$tmpfile <<EOF
+del utimes_test
+put ${SMBCLIENT} utimes_test
+allinfo utimes_test
+utimes utimes_test 2016:02:04-06:19:20 17:01:01-05:10:20 -1 -1
+allinfo utimes_test
+del utimes_test
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+
+ if [ -n "$saved_TZ" ]; then
+ export TZ="$saved_TZ"
+ else
+ unset TZ
+ fi
+ if [ -n "$saved_LANG" ]; then
+ export LANG="$saved_LANG"
+ else
+ unset LANG
+ fi
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed utimes test with output $ret"
+ false
+ return
+ fi
+
+ # Now, we should have 2 identical write_time and change_time
+ # values, but one access_time of Jan 1 05:10:20 AM,
+ # and one create_time of Feb 04 06:19:20 AM 2016
+ out_sorted=$(echo "$out" | sort | uniq)
+ num_create=$(echo "$out_sorted" | grep -c 'create_time:')
+ num_access=$(echo "$out_sorted" | grep -c 'access_time:')
+ num_write=$(echo "$out_sorted" | grep -c 'write_time:')
+ num_change=$(echo "$out_sorted" | grep -c 'change_time:')
+ if [ "$num_create" != "2" ]; then
+ echo "failed - should get two create_time $out"
+ false
+ return
+ fi
+ if [ "$num_access" != "2" ]; then
+ echo "failed - should get two access_time $out"
+ false
+ return
+ fi
+ if [ "$num_write" != "1" ]; then
+ echo "failed - should only get one write_time $out"
+ false
+ return
+ fi
+ if [ "$num_change" != "1" ]; then
+ echo "failed - should only get one change_time $out"
+ false
+ return
+ fi
+
+ # This could be: Sun Jan 1 05:10:20 AM 2017
+ # or : Sun Jan 1 05:10:20 2017 CET
+ echo "$out" | grep 'access_time:.*Sun Jan.*1 05:10:20 .*2017.*'
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo
+ echo "failed - should get access_time: Sun Jan 1 05:10:20 [AM] 2017"
+ false
+ return
+ fi
+
+ # This could be: Thu Feb 4 06:19:20 AM 2016
+ # or : Thu Feb 4 06:19:20 2016 CET
+ echo "$out" | grep 'create_time:.*Thu Feb.*4 06:19:20 .*2016.*'
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo
+ echo "failed - should get access_time: Thu Feb 4 06:19:20 [AM] 2016"
+ false
+ return
+ fi
+}
+
+# Test smbclient renames with pathnames containing '..'
+test_rename_dotdot()
+{
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+
+ cat >$tmpfile <<EOF
+deltree dotdot_test
+mkdir dotdot_test
+cd dotdot_test
+mkdir dir1
+mkdir dir2
+cd dir1
+put ${SMBCLIENT} README
+rename README ..\\dir2\\README
+cd ..
+cd dir2
+allinfo README
+cd \\
+deltree dotdot_test
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed rename_dotdot test with output $ret"
+ false
+ return
+ fi
+
+ # We are allowed to get NT_STATUS_NO_SUCH_FILE listing \dotdot_test
+ # as the top level directory should not exist, but no other errors.
+
+ error_str=$(echo $out | grep NT_STATUS | grep -v "NT_STATUS_NO_SUCH_FILE listing .dotdot_test")
+ if [ "$error_str" != "" ]; then
+ echo "failed - unexpected NT_STATUS error in $out"
+ false
+ return
+ fi
+}
+
+# Test doing a volume command.
+test_volume()
+{
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ cat >$tmpfile <<EOF
+volume
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed doing volume command with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep '^Volume: |tmp| serial number'
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed doing volume command"
+ return 1
+ fi
+}
+
+test_server_os_message()
+{
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ cat >$tmpfile <<EOF
+ls
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "failed to connect error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep 'Try "help" to get a list of possible commands.'
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo 'failed - should get: Try "help" to get a list of possible commands.'
+ return 1
+ fi
+
+ return 0
+}
+
+test_server_quiet_message()
+{
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ cat >$tmpfile <<EOF
+ls
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS --quiet < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "failed to connect error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep 'Try "help" to get a list of possible commands.'
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "$out"
+ echo 'failed - quiet should skip this message.'
+ return 1
+ fi
+
+ return 0
+}
+
+# Test xattr_stream correctly reports mode.
+# BUG: https://bugzilla.samba.org/show_bug.cgi?id=13380
+
+test_stream_directory_xattr()
+{
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ #
+ # Test against streams_xattr
+ #
+ cat >$tmpfile <<EOF
+deltree foo
+mkdir foo
+put ${PREFIX}/smbclient_interactive_prompt_commands foo:bar
+setmode foo -a
+allinfo foo:bar
+deltree foo
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/streams_xattr -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed checking attributes on xattr stream foo:bar with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep "attributes:.*80"
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed checking attributes on xattr stream foo:bar"
+ return 1
+ fi
+
+ #
+ # Test against streams_depot
+ #
+ cat >$tmpfile <<EOF
+deltree foo
+mkdir foo
+put ${PREFIX}/smbclient_interactive_prompt_commands foo:bar
+setmode foo -a
+allinfo foo:bar
+deltree foo
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed checking attributes on depot stream foo:bar with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep "attributes:.*80"
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed checking attributes on depot stream foo:bar"
+ return 1
+ fi
+}
+
+# Test smbclient non-empty rmdir command
+test_del_nedir()
+{
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ del_nedir="$LOCAL_PATH/del_nedir"
+
+ rm -rf $del_nedir
+ mkdir $del_nedir
+ touch $del_nedir/afile
+ cat >$tmpfile <<EOF
+rmdir del_nedir
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -rf $del_nedir
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed test_del_nedir test with output $ret"
+ false
+ return
+ fi
+
+ # Should get NT_STATUS_DIRECTORY_NOT_EMPTY error from rmdir
+ echo "$out" | grep 'NT_STATUS_DIRECTORY_NOT_EMPTY'
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "test_del_nedir failed - should get an NT_STATUS_DIRECTORY_NOT_EMPTY error"
+ false
+ return
+ fi
+}
+
+test_valid_users()
+{
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ cat >$tmpfile <<EOF
+ls
+quit
+EOF
+ # User in "valid users" can login to service
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$DC_USERNAME%$DC_PASSWORD //$SERVER/valid_users $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "test_valid_users:valid_users 'User in 'valid users' can login to service' failed - $ret"
+ return 1
+ fi
+
+ # User from ad group in "valid users" can login to service
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$DC_USERNAME%$DC_PASSWORD //$SERVER/valid_users_group $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "test_valid_users:valid_users_group 'User from ad group in 'valid users' can login to service' failed - $ret"
+ return 1
+ fi
+
+ # User from UNIX group in "valid users" can login to service
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$DC_USERNAME%$DC_PASSWORD //$SERVER/valid_users_unix_group $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "test_valid_users:valid_users_unix_group 'User from UNIX group in 'valid users' can login to service' failed - $ret"
+ return 1
+ fi
+
+ # User not in NIS group in "valid users" can't login to service
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$DC_USERNAME%$DC_PASSWORD //$SERVER/valid_users_nis_group $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ echo "$out" | grep 'NT_STATUS_ACCESS_DENIED'
+ ret=$?
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "test_valid_users:valid_users_nis_group 'User not in NIS group in 'valid users' can't login to service' failed - $ret"
+ return 1
+ fi
+
+ # Check user in UNIX, then in NIS group in "valid users" can login to service
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$DC_USERNAME%$DC_PASSWORD //$SERVER/valid_users_unix_nis_group $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "test_valid_users:valid_users_unix_nis_group 'Check user in UNIX, then in NIS group in 'valid users' can login to service' failed - $ret"
+ return 1
+ fi
+
+ # Check user in NIS, then in UNIX group in "valid users" can login to service
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$DC_USERNAME%$DC_PASSWORD //$SERVER/valid_users_nis_unix_group $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "test_valid_users:valid_users_nis_unix_group 'Check user in NIS, then in UNIX group in 'valid users' can login to service' failed - $ret"
+ return 1
+ fi
+
+ # User not in "invalid users" can login to service
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -Ualice%Secret007 //$SERVER/invalid_users $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "test_valid_users:invalid_users 'User not in 'invalid users' can login to service' failed - $ret"
+ return 1
+ fi
+
+ # User in "invalid users" can't login to service
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$DC_USERNAME%$DC_PASSWORD //$SERVER/invalid_users $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ echo "$out" | grep 'NT_STATUS_ACCESS_DENIED'
+ ret=$?
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "test_valid_users:invalid_users 'User in 'invalid users' can't login to service' failed - $ret"
+ return 1
+ fi
+
+ # User is in "valid and invalid users" can't login to service
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$DC_USERNAME%$DC_PASSWORD //$SERVER/valid_and_invalid_users $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ echo "$out" | grep 'NT_STATUS_ACCESS_DENIED'
+ ret=$?
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "test_valid_users:valid_and_invalid_users 'User is in 'valid and invalid users' can't login to service' failed - $ret"
+ return 1
+ fi
+
+ # 2 Users are in "valid users"
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -Ualice%Secret007 //$SERVER/valid_and_invalid_users $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "test_valid_users:valid_and_invalid_users '2 Users are in 'valid users'' failed - $ret"
+ return 1
+ fi
+
+ return 0
+}
+
+test_smbclient_minus_e_stderr()
+{
+ cmd='$SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -c ls'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ if [ $? != 0 ]; then
+ echo "$out"
+ echo "command failed"
+ return 1
+ fi
+
+ # test smbclient 'ls' command output went to stdout
+ echo "$out" | grep "blocks available" >/dev/null 2>&1
+ if [ $? != 0 ]; then
+ # didn't get output to stdout
+ echo "expected output was NOT output to stdout"
+ return 1
+ fi
+
+ # this time execute ls but redirect stdout alone to /dev/null
+ cmd='$SMBCLIENT -E "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -c "ls" 2>&1 > /dev/null'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ if [ $? != 0 ]; then
+ echo "$out"
+ echo "command failed"
+ return 1
+ fi
+
+ # test smbclient 'ls' command output went to stderr
+ echo "$out" | grep "blocks available" >/dev/null 2>&1
+ if [ $? != 0 ]; then
+ # didn't get output to stderr
+ echo "expected output was NOT output to stderr"
+ return 1
+ fi
+
+ return 0
+
+}
+
+#
+#
+LOGDIR_PREFIX=test_smbclient_s3
+
+# possibly remove old logdirs:
+
+for OLDDIR in $(find ${PREFIX} -type d -name "${LOGDIR_PREFIX}_*"); do
+ echo "removing old directory ${OLDDIR}"
+ rm -rf ${OLDDIR}
+done
+
+LOGDIR=$(mktemp -d ${PREFIX}/${LOGDIR_PREFIX}_XXXXXX)
+
+testit "smbclient -L $SERVER_IP" $SMBCLIENT -L $SERVER_IP -N -p 139 ${RAWARGS} || failed=$(expr $failed + 1)
+testit "smbclient -L $SERVER -I $SERVER_IP" $SMBCLIENT -L $SERVER -I $SERVER_IP -N -p 139 ${RAWARGS} -c quit || failed=$(expr $failed + 1)
+
+testit "noninteractive smbclient does not prompt" \
+ test_noninteractive_no_prompt ||
+ failed=$(expr $failed + 1)
+
+testit "noninteractive smbclient -l does not prompt" \
+ test_noninteractive_no_prompt -l $LOGDIR ||
+ failed=$(expr $failed + 1)
+
+testit "smbclient output goes to stderr when -E is passed" \
+ test_smbclient_minus_e_stderr ||
+ failed=$(expr $failed + 1)
+
+testit "interactive smbclient prompts on stdout" \
+ test_interactive_prompt_stdout ||
+ failed=$(expr $failed + 1)
+
+testit "interactive smbclient -l prompts on stdout" \
+ test_interactive_prompt_stdout -l $LOGDIR ||
+ failed=$(expr $failed + 1)
+
+testit "creating a bad symlink and deleting it" \
+ test_bad_symlink ||
+ failed=$(expr $failed + 1)
+
+testit "creating a good symlink and deleting it by path" \
+ test_good_symlink ||
+ failed=$(expr $failed + 1)
+
+testit "writing into a read-only directory fails" \
+ test_read_only_dir ro-tmp ||
+ failed=$(expr $failed + 1)
+
+testit "writing into a read-only share fails" \
+ test_read_only_dir valid-users-tmp ||
+ failed=$(expr $failed + 1)
+
+testit "Reading a owner-only file fails" \
+ test_owner_only_file ||
+ failed=$(expr $failed + 1)
+
+testit "Accessing an MS-DFS link" \
+ test_msdfs_link ||
+ failed=$(expr $failed + 1)
+
+testit "Recursive ls across MS-DFS links" \
+ test_msdfs_recursive_dir ||
+ failed=$(expr $failed + 1)
+
+testit "Rename on MS-DFS share" \
+ test_msdfs_rename ||
+ failed=$(expr $failed + 1)
+
+testit "Hardlink on MS-DFS share" \
+ test_msdfs_hardlink ||
+ failed=$(expr $failed + 1)
+
+testit "del on MS-DFS share" \
+ test_msdfs_del || \
+ failed=`expr $failed + 1`
+
+testit "deltree on MS-DFS share" \
+ test_msdfs_deltree || \
+ failed=`expr $failed + 1`
+
+testit "Ensure archive bit is set correctly on file/dir rename" \
+ test_rename_archive_bit ||
+ failed=$(expr $failed + 1)
+
+testit "ccache access works for smbclient" \
+ test_ccache_access ||
+ failed=$(expr $failed + 1)
+
+testit "sending a message to the remote server" \
+ test_message ||
+ failed=$(expr $failed + 1)
+
+testit "using an authentication file" \
+ test_auth_file ||
+ failed=$(expr $failed + 1)
+
+testit "list with backup privilege" \
+ test_backup_privilege_list ||
+ failed=$(expr $failed + 1)
+
+testit "list a share with bad names (won't convert)" \
+ test_bad_names ||
+ failed=$(expr $failed + 1)
+
+testit "list a share with a mangled name + acl_xattr object" \
+ test_mangled_names ||
+ failed=$(expr $failed + 1)
+
+testit "server-side file copy" \
+ test_scopy ||
+ failed=$(expr $failed + 1)
+
+testit "creating a :stream at root of share" \
+ test_toplevel_stream ||
+ failed=$(expr $failed + 1)
+
+testit "Ensure widelinks are restricted" \
+ test_widelinks ||
+ failed=$(expr $failed + 1)
+
+testit "streams_depot can delete correctly" \
+ test_streams_depot_delete ||
+ failed=$(expr $failed + 1)
+
+testit "stream_xattr attributes" \
+ test_stream_directory_xattr ||
+ failed=$(expr $failed + 1)
+
+testit "follow symlinks = no" \
+ test_nosymlinks ||
+ failed=$(expr $failed + 1)
+
+testit "follow local symlinks" \
+ test_local_symlinks ||
+ failed=$(expr $failed + 1)
+
+testit "noperm share regression" \
+ test_noperm_share_regression ||
+ failed=$(expr $failed + 1)
+
+testit "smbclient deltree command" \
+ test_deltree ||
+ failed=$(expr $failed + 1)
+
+testit "server os message" \
+ test_server_os_message ||
+ failed=$(expr $failed + 1)
+
+testit "test server quiet message" \
+ test_server_quiet_message ||
+ failed=$(expr $failed + 1)
+
+testit "setmode test" \
+ test_setmode ||
+ failed=$(expr $failed + 1)
+
+testit "utimes" \
+ test_utimes ||
+ failed=$(expr $failed + 1)
+
+testit "rename_dotdot" \
+ test_rename_dotdot ||
+ failed=$(expr $failed + 1)
+
+testit "volume" \
+ test_volume ||
+ failed=$(expr $failed + 1)
+
+testit "rm -rf $LOGDIR" \
+ rm -rf $LOGDIR ||
+ failed=$(expr $failed + 1)
+
+testit "delete a non empty directory" \
+ test_del_nedir ||
+ failed=$(expr $failed + 1)
+
+testit "valid users" \
+ test_valid_users ||
+ failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_smbclient_tarmode.pl b/source3/script/tests/test_smbclient_tarmode.pl
new file mode 100755
index 0000000..fa69d28
--- /dev/null
+++ b/source3/script/tests/test_smbclient_tarmode.pl
@@ -0,0 +1,1723 @@
+#!/usr/bin/perl
+# Unix SMB/CIFS implementation.
+# Test suite for the tar backup mode of smbclient.
+# Copyright (C) Aurélien Aptel 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/>.
+
+=head1 NAME
+
+C<test_smbclient_tarmode.pl> - Test for smbclient tar backup feature
+
+=cut
+
+use v5.10;
+use strict;
+use warnings;
+
+use Archive::Tar;
+use Data::Dumper;
+use Digest::MD5 qw/md5_hex/;
+use File::Path qw/make_path remove_tree/;
+use File::Spec;
+use File::Temp;
+use Getopt::Long;
+use Pod::Usage;
+use Term::ANSIColor;
+
+sub d {print Dumper @_;}
+
+# DEFAULTS
+# 'our' to make them available in the File package
+our $USER = '';
+our $PW = '';
+our $HOST = '';
+our $IP = '';
+our $SHARE = '';
+our $DIR = 'tar_test_dir';
+our $LOCALPATH = '';
+our $TMP = File::Temp->newdir();
+our $BIN = 'smbclient';
+our $SUBUNIT = 0;
+
+my $SELECTED_TEST = '';
+my $LIST_TEST = 0;
+
+my @SMBARGS = ();
+
+our $DEBUG = 0;
+our $VERBOSE = 0;
+my $MAN = 0;
+my $HELP = 0;
+my $CLEAN = 0;
+
+# all tests
+my @TESTS = (
+# ['test helper', \&test_helper],
+ ['create, normal files (no attributes)', \&test_creation_normal, 'normal'],
+ ['create, normal nested files (no attributes)', \&test_creation_normal, 'nested'],
+ ['create, normal files (interactive)', \&test_creation_normal, 'inter'],
+ ['create, large file', \&test_creation_large_file],
+ ['create, long path', \&test_creation_long_path],
+ ['create, incremental with -g', \&test_creation_incremental, '-g'],
+ ['create, incremental with tarmode', \&test_creation_incremental, 'tarmode inc'],
+ ['create, reset archived files with -a', \&test_creation_reset, '-a'],
+ ['create, reset archived files with tarmode', \&test_creation_reset, 'tarmode reset'],
+ ['create, files newer than a file', \&test_creation_newer],
+ ['create, combination of tarmode filter', \&test_creation_attr],
+ ['create, explicit include', \&test_creation_include],
+ ['create, explicit exclude', \&test_creation_exclude],
+ ['create, include w/ filelist (F)', \&test_creation_list],
+ ['create, wildcard simple', \&test_creation_wildcard_simple],
+ ['create, regex', \&test_creation_regex],
+ ['create, multiple backup in session', \&test_creation_multiple],
+ ['extract, normal files', \&test_extraction_normal],
+ ['extract, explicit include', \&test_extraction_include],
+ ['extract, explicit exclude', \&test_extraction_exclude],
+ ['extract, include w/ filelist (F)', \&test_extraction_list],
+ ['extract, regex', \&test_extraction_regex],
+);
+
+=head1 SYNOPSIS
+
+ test_smbclient_tarmode.pl [options] -- [smbclient options]
+
+ Options:
+ -h, --help brief help message
+ --man full documentation
+
+ Environment:
+ -u, --user USER
+ -p, --password PW
+ -n, --name HOST (required)
+ -i, --ip IP
+ -s, --share SHARE (required)
+ -d, --dir PATH
+ sub-path to use on the share
+
+ -l, --local-path PATH (required)
+ path to the root of the samba share on the machine.
+
+ -b, --bin BIN
+ path to the smbclient binary to use
+
+ Test:
+ --list
+ list tests
+
+ --test N
+ --test A-B
+ --test A,B,D-F
+ only run certain tests (accept list and intervals of numbers)
+
+ -v, --verbose
+ be more verbose
+
+ --debug
+ print command and their output (also set -v)
+
+ --subunit
+ print output in subunit format
+
+=cut
+
+GetOptions('u|user=s' => \$USER,
+ 'p|password=s' => \$PW,
+ 'n|name=s' => \$HOST,
+ 'i|ip=s' => \$IP,
+ 's|share=s' => \$SHARE,
+ 'd|dir=s' => \$DIR,
+ 'l|local-path=s' => \$LOCALPATH,
+ 'b|bin=s' => \$BIN,
+
+ 'test=s' => \$SELECTED_TEST,
+ 'list' => \$LIST_TEST,
+
+ 'clean' => \$CLEAN,
+ 'subunit' => \$SUBUNIT,
+ 'debug' => \$DEBUG,
+ 'v|verbose' => \$VERBOSE,
+ 'h|help' => \$HELP,
+ 'man' => \$MAN) or pod2usage(2);
+
+pod2usage(0) if $HELP;
+pod2usage(-exitval => 0, -verbose => 2) if $MAN;
+list_test(), exit 0 if $LIST_TEST;
+pod2usage(1) unless $HOST;
+pod2usage(1) unless $SHARE;
+pod2usage(1) unless $LOCALPATH;
+
+if ($USER xor $PW) {
+ die "Need both user and password when one is provided\n";
+}
+elsif ($USER and $PW) {
+ push @SMBARGS, '-U'.$USER.'%'.$PW;
+}
+else {
+ push @SMBARGS, '-N';
+}
+
+if ($IP) {
+ push @SMBARGS, '-I', $IP;
+}
+
+# remaining arguments are passed to smbclient
+push @SMBARGS, @ARGV;
+
+# path to store the downloaded tarball
+my $TAR = "$TMP/tarmode.tar";
+
+#####
+
+# SANITIZATION
+
+# remove all final slashes from input paths
+$LOCALPATH =~ s{[/\\]+$}{}g;
+$SHARE =~ s{[/\\]+$}{}g;
+$HOST =~ s{[/\\]+$}{}g;
+$DIR =~ s{^\.[/\\]+$}{}g;
+$DIR =~ s{[/\\]+$}{}g;
+
+if (!-d $LOCALPATH) {
+ die "Local path '$LOCALPATH' is not a directory.\n";
+}
+
+if ($CLEAN) {
+ # clean the whole root first
+ remove_tree($LOCALPATH, { keep_root => 1 });
+}
+
+if ($DEBUG) {
+ $VERBOSE = 1;
+}
+
+#####
+
+# RUN TESTS
+
+my @selection = parse_test_string($SELECTED_TEST);
+
+if ($SELECTED_TEST eq '') {
+ run_test(@TESTS);
+} elsif (@selection > 0) {
+ run_test(@selection);
+} else {
+ die "Test selection '$SELECTED_TEST' is invalid\n";
+}
+
+#################################
+
+=head1 DOCUMENTATION
+
+=head2 Defining a test
+
+=over
+
+=item * Create a function C<test_yourtest>
+
+=item * Use the File module, documented below
+
+=item * Use C<smb_tar>, C<smb_client>, C<check_tar> or C<check_remote>
+
+=item * Return number of error
+
+=item * Add function to C<@TESTS>
+
+=back
+
+The function must be placed in the C<@TESTS> list along with a short
+description and optional arguments.
+
+=cut
+
+sub test_creation_newer {
+ my @files;
+ my $dt = 3000;
+
+ # create oldest file at - DT
+ my $oldest = File->new_remote('oldest');
+ $oldest->set_time(time - $dt);
+
+ # create limit file
+ my $limit = File->new_local("$TMP/limit");
+
+ # create newA file at + DT
+ my $newA = File->new_remote('newA');
+ $newA->set_time(time + $dt);
+
+ # create newB file at + DT
+ my $newB = File->new_remote('newB');
+ $newB->set_time(time + $dt);
+
+ # get files newer than limit_file
+ push @files, $newA, $newB;
+
+ smb_tar('', '-TcN', $limit->localpath, $TAR, $DIR);
+ return check_tar($TAR, \@files);
+}
+
+sub test_creation_attr {
+ my @attr = qw/r h s a/;
+ my @all;
+ my @inc;
+ my $err = 0;
+
+ # one normal file
+ my $f = File->new_remote("file-n.txt");
+ push @all, $f;
+
+ # combinations of attributes
+ for my $n (1..@attr) {
+ for (combine(\@attr, $n)) {
+ my @t = @$_;
+ my $fn = "file-" . join('+', @t) . ".txt";
+ my $f = File->new_remote($fn);
+ $f->set_attr(@t);
+ push @all, $f;
+ }
+ }
+
+ @inc = grep { !$_->attr('s') } @all;
+ smb_tar('tarmode nosystem', '-Tc', $TAR, $DIR);
+ $err += check_tar($TAR, \@inc);
+
+ @inc = grep { !$_->attr('h') } @all;
+ smb_tar('tarmode nohidden', '-Tc', $TAR, $DIR);
+ $err += check_tar($TAR, \@inc);
+
+ @inc = grep { !$_->attr_any('h', 's') } @all;
+ smb_tar('tarmode nohidden nosystem', '-Tc', $TAR, $DIR);
+ $err += check_tar($TAR, \@inc);
+
+ @inc = grep { $_->attr('a') && !$_->attr_any('h', 's') } @all;
+ smb_tar('tarmode inc nohidden nosystem', '-Tc', $TAR, $DIR);
+ $err += check_tar($TAR, \@inc);
+ # adjust attr so remote files can be deleted with deltree
+ File::walk(sub { $_->set_attr(qw/n r s h/) }, File::tree($DIR));
+
+ $err;
+}
+
+sub test_creation_reset {
+ my ($mode) = @_;
+
+ my @files;
+ my $n = 3;
+ for (1..$n) {
+ my $f = File->new_remote("file-$_");
+ $f->set_attr('a');
+ push @files, $f;
+ }
+
+ if ($mode =~ /reset/) {
+ smb_tar('tarmode full reset', '-Tc', $TAR, $DIR);
+ } else {
+ smb_tar('', '-Tca', $TAR, $DIR);
+ }
+
+ my $err = check_tar($TAR, \@files);
+ return $err if ($err > 0);
+
+ for my $f (File::list($DIR)) {
+ if ($f->{attr}{a}) {
+ printf " ! %s %s\n", $f->attr_str, $f->remotepath;
+ $err++;
+ }
+ }
+ return $err;
+}
+
+sub test_creation_large_file {
+ my $size = int(15e6); # 15MB
+ my $f = File->new_remote("fat.jpg", 0, $size);
+
+ smb_tar('', '-Tc', $TAR, $DIR);
+ return check_tar($TAR, [$f]);
+}
+
+sub test_creation_long_path {
+ my $d = "a"x130;
+ my @all;
+
+ for (qw( foo/a bar/b )) {
+ push @all, File->new_remote("$d/$_");
+ }
+
+ smb_tar('', '-Tc', $TAR, $DIR);
+ return check_tar($TAR, \@all);
+}
+
+sub test_creation_normal {
+ my ($mode) = @_;
+
+ my $prefix = ($mode =~ /nest/) ? "/foo/bar/bar/" : '';
+ my @files;
+ my $n = 5;
+ for (1..$n) {
+ my $f = File->new_remote($prefix."file-$_");
+ push @files, $f;
+ }
+
+ if ($mode =~ /inter/) {
+ smb_tar("tar c $TAR $DIR", '');
+ } else {
+ smb_tar('tarmode full', '-Tc', $TAR, $DIR);
+ }
+ return check_tar($TAR, \@files);
+}
+
+sub test_creation_incremental {
+ my ($mode) = @_;
+
+ my @files;
+ my $n = 10;
+ for (1..$n) {
+ my $f = File->new_remote("file-$_");
+
+ # set archive bit on ~half of them
+ if ($_ < $n/2) {
+ $f->set_attr('a');
+ push @files, $f;
+ }
+ else {
+ $f->set_attr((qw/n r s h/)[$_ % 4]);
+ }
+ }
+
+ if ($mode =~ /inc/) {
+ smb_tar('tarmode inc', '-Tc', $TAR, $DIR);
+ } else {
+ smb_tar('', '-Tcg', $TAR, $DIR);
+ }
+ my $res = check_tar($TAR, \@files);
+ # adjust attr so remote files can be deleted with deltree
+ File::walk(sub { $_->set_attr(qw/n r s h/) }, File::tree($DIR));
+ return $res
+}
+
+
+sub test_extraction_normal {
+ my @files;
+ my $n = 5;
+ for (1..$n) {
+ my $f = File->new_remote("file-$_");
+ push @files, $f;
+ }
+
+ # store
+ smb_tar('', '-Tc', $TAR, $DIR);
+ my $err = check_tar($TAR, \@files);
+ return $err if $err > 0;
+
+ reset_remote();
+
+ smb_tar('', '-Tx', $TAR);
+ check_remote($DIR, \@files);
+}
+
+sub test_extraction_include {
+ my @all_files;
+ my @inc_files;
+
+ for (qw(file_inc inc/b inc/c inc/dir/foo dir_ex/d zob)) {
+ my $f = File->new_remote($_);
+ push @all_files, $f;
+ push @inc_files, $f if /inc/;
+ }
+
+ # store
+ smb_tar('', '-Tc', $TAR, $DIR);
+ my $err = check_tar($TAR, \@all_files);
+ return $err if $err > 0;
+
+ reset_remote();
+
+ smb_tar('', '-TxI', $TAR, "$DIR/file_inc", "$DIR/inc");
+ check_remote($DIR, \@inc_files);
+}
+
+sub test_extraction_exclude {
+ my @all_files;
+ my @inc_files;
+
+ for (qw(file_exc exc/b exc/c exc/dir/foo dir_ex/d zob)) {
+ my $f = File->new_remote($_);
+ push @all_files, $f;
+ push @inc_files, $f if !/exc/;
+ }
+
+ # store
+ smb_tar('', '-Tc', $TAR, $DIR);
+ my $err = check_tar($TAR, \@all_files);
+ return $err if $err > 0;
+
+ reset_remote();
+
+ smb_tar('', '-TxX', $TAR, "$DIR/file_exc", "$DIR/exc");
+ check_remote($DIR, \@inc_files);
+}
+
+
+sub test_creation_include {
+ my @files;
+
+ for (qw(file_inc inc/b inc/c inc/dir/foo dir_ex/d zob)) {
+ my $f = File->new_remote($_);
+ push @files, $f if /inc/;
+ }
+
+ smb_tar('', '-TcI', $TAR, "$DIR/file_inc", "$DIR/inc");
+ return check_tar($TAR, \@files);
+}
+
+sub test_creation_exclude {
+ my @files;
+
+ for (qw(file_ex ex/b ex/c ex/dir/foo foo/bar zob)) {
+ my $f = File->new_remote($_);
+ push @files, $f if !/ex/;
+ }
+
+ smb_tar('', '-TcX', $TAR, "$DIR/file_ex", "$DIR/ex");
+ return check_tar($TAR, \@files);
+}
+
+sub test_creation_list {
+ my @inc_files;
+
+ for (qw(file_inc inc/b inc/c inc/dir/foo foo/bar zob)) {
+ my $f = File->new_remote($_);
+ push @inc_files, $f if /inc/;
+ }
+
+ my $flist = File->new_local("$TMP/list", file_list(@inc_files));
+ smb_tar('', '-TcF', $TAR, $flist->localpath);
+ return check_tar($TAR, \@inc_files);
+}
+
+sub test_creation_regex {
+ my @exts = qw(jpg exe);
+ my @dirs = ('', "$DIR/");
+ my @all = make_env(\@exts, \@dirs);
+ my $nb;
+ my @inc;
+ my $err = 0;
+
+ # EXCLUSION
+
+ # skip *.exe
+ @inc = grep { $_->remotepath !~ m{exe$} } @all;
+ smb_tar('', '-TcrX', $TAR, '*.exe');
+ $err += check_tar($TAR, \@inc);
+
+ # if the pattern is a path, it doesn't skip anything
+ smb_tar('', '-TcrX', $TAR, "$DIR/*.exe");
+ $err += check_tar($TAR, \@all);
+ smb_tar('', '-TcrX', $TAR, "$DIR/*");
+ $err += check_tar($TAR, \@all);
+ smb_tar('', '-TcrX', $TAR, "$DIR");
+ $err += check_tar($TAR, \@all);
+
+ # no paths => include everything
+ smb_tar('', '-TcrX', $TAR);
+ $err += check_tar($TAR, \@all);
+
+
+ # skip everything
+ smb_tar('', '-TcrX', $TAR, "*.*");
+ $err += check_tar($TAR, []);
+ smb_tar('', '-TcrX', $TAR, "*");
+ $err += check_tar($TAR, []);
+
+ # INCLUSION
+
+ # no paths => include everything
+ smb_tar('', '-Tcr', $TAR);
+ $err += check_tar($TAR, \@all);
+
+ # include everything
+ smb_tar('', '-Tcr', $TAR, '*');
+ $err += check_tar($TAR, \@all);
+
+ # include only .exe at root
+ @inc = grep { $_->remotepath =~ m{^[^/]+exe$}} @all;
+ smb_tar('', '-Tcr', $TAR, '*.exe');
+ $err += check_tar($TAR, \@inc);
+
+ # smb_tar('', '-Tcr', $TAR, "$DIR/*");
+ ## in old version (bug?)
+ # $err += check_tar($TAR, []);
+ ## in rewrite
+ # @inc = grep { $_->remotepath =~ /^$DIR/ } @all;
+ # $err += check_tar($TAR, \@inc);
+
+ $err;
+}
+
+sub test_creation_wildcard_simple {
+ my @exts = qw(jpg exe);
+ my @dirs = ('', "$DIR/");
+ my @all = make_env(\@exts, \@dirs);
+ my $nb;
+ my @inc;
+ my $err = 0;
+
+ @inc = grep { $_->remotepath =~ m{^[^/]+exe$} } @all;
+ smb_tar('', '-Tc', $TAR, "*.exe");
+ $err += check_tar($TAR, \@inc);
+
+ @inc = grep { $_->remotepath =~ m{$DIR/.+exe$} } @all;
+ smb_tar('', '-Tc', $TAR, "$DIR/*.exe");
+ $err += check_tar($TAR, \@inc);
+
+ $err;
+}
+
+# NOT USED
+# helper to test tests
+sub test_helper {
+ my @exts = qw(txt jpg exe);
+ my @dirs = ('', "$DIR/", "$DIR/dir/");
+ my @all = make_env(\@exts, \@dirs);
+ my $nb;
+ my $err = 0;
+ my @inc;
+
+ smb_tar('', '-Tc', $TAR);
+ return 1 if check_tar($TAR, \@all);
+ reset_remote();
+
+ my @exc = grep { $_->remotepath =~ m!/dir/.+exe!} @all;
+ @inc = grep { $_->remotepath !~ m!/dir/.+exe!} @all;
+ smb_tar('', '-TxXr', $TAR, "/$DIR/dir/*.exe");
+ $err += check_remote('/', \@all); # BUG: should be \@inc
+ reset_remote();
+
+ return 0;
+}
+
+sub test_creation_multiple {
+ my @exts = qw(jpg exe);
+ my @dirs = ('', "$DIR/");
+ my @all = make_env(\@exts, \@dirs);
+ my $nb;
+ my @inc;
+ my $err = 0;
+
+ my ($tarA, $tarB) = ("$TMP/a.tar", "$TMP/b.tar");
+ my @incA = grep { $_->remotepath =~ m{^[^/]+exe$} } @all;
+ my @incB = grep { $_->remotepath =~ m{^[^/]+jpg$} } @all;
+
+ my $flistA = File->new_local("$TMP/listA", file_list(@incA))->localpath;
+ my $flistB = File->new_local("$TMP/listB", file_list(@incB))->localpath;
+
+ smb_tar("tar cF $tarA $flistA ; tar cF $tarB $flistB ; quit");
+ $err += check_tar($tarA, \@incA);
+ $err += check_tar($tarB, \@incB);
+
+ $err;
+}
+
+sub test_extraction_regex {
+ my @exts = qw(txt jpg exe);
+ my @dirs = ('', "$DIR/", "$DIR/dir/");
+ my @all = make_env(\@exts, \@dirs);
+ my $nb;
+ my $err = 0;
+ my (@inc, @exc);
+
+ smb_tar('', '-Tc', $TAR);
+ return 1 if check_tar($TAR, \@all);
+ reset_remote();
+
+ # INCLUDE
+
+ # only include file at root
+ @inc = grep { $_->remotepath =~ m!exe!} @all;
+ smb_tar('', '-Txr', $TAR, "*.exe");
+ $err += check_remote('/', \@inc);
+ reset_remote();
+
+ @inc = grep { $_->remotepath =~ m!/dir/.+exe!} @all;
+ smb_tar('', '-Txr', $TAR, "/$DIR/dir/*.exe");
+ $err += check_remote('/', []); # BUG: should be \@inc
+ reset_remote();
+
+ # EXCLUDE
+
+ # exclude file not directly at root
+ @inc = grep { $_->remotepath =~ m!^[^/]+$!} @all;
+ @exc = grep { $_->remotepath !~ m!^[^/]+$!} @all;
+ smb_tar('', '-TxrX', $TAR, map {$_->remotepath} @exc);
+ $err += check_remote('/', \@all); # BUG: should be @inc...
+ reset_remote();
+
+ # exclude only $DIR/dir/*exe
+ @exc = grep { $_->remotepath =~ m!/dir/.+exe!} @all;
+ @inc = grep { $_->remotepath !~ m!/dir/.+exe!} @all;
+ smb_tar('', '-TxXr', $TAR, "/$DIR/dir/*.exe");
+ $err += check_remote('/', \@all); # BUG: should be \@inc
+ reset_remote();
+
+ $err;
+}
+
+sub test_extraction_wildcard {
+ my @exts = qw(txt jpg exe);
+ my @dirs = ('', "$DIR/", "$DIR/dir/");
+ my $nb;
+ my $err = 0;
+
+ for my $dir (@dirs) {
+
+ my @all;
+
+ $nb = 0;
+ for my $dir (@dirs) {
+ for (@exts) {
+ my $fn = $dir . "file$nb." . $_;
+ my $f = File->new_remote($fn, 'ABSPATH');
+ $f->delete_on_destruction(1);
+ push @all, $f;
+ $nb++;
+ }
+ }
+
+
+ my @inc;
+ my $ext = 'exe';
+ my $fn = $dir."file$nb.".$ext;
+ my $pattern = $dir.'*.'.$ext;
+ my $flist;
+
+ # with F
+
+ $flist = File->new_local("$TMP/list", "$pattern\n");
+
+ # store
+ my $re = '^'.$dir.'.*file';
+ @inc = grep { $dir eq '' or $_->remotepath =~ m{$re} } @all;
+ smb_tar('', '-Tc', $TAR, $dir);
+ $err += check_tar($TAR, \@inc);
+
+ reset_remote();
+ my $re2 = '^'.$dir.'file.+exe';
+ @inc = grep { $_->remotepath =~ /$re2/ } @all;
+ smb_tar('', '-TxrF', $TAR, $flist->localpath);
+ $err += check_remote($dir, \@inc);
+
+ reset_remote();
+ }
+
+ $err;
+}
+
+sub test_extraction_list {
+ my @inc_files;
+ my @all_files;
+
+ for (qw(file_inc inc/b inc/c inc/dir/foo foo/bar zob)) {
+ my $f = File->new_remote($_);
+ push @all_files, $f;
+ push @inc_files, $f if /inc/;
+ }
+
+ # store
+ smb_tar('', '-Tc', $TAR, $DIR);
+ my $err = check_tar($TAR, \@all_files);
+ return $err if $err > 0;
+
+ reset_remote();
+
+ my $flist = File->new_local("$TMP/list", file_list(@inc_files));
+ smb_tar('', '-TxF', $TAR, $flist->localpath);
+ return check_remote($DIR, \@inc_files);
+}
+
+#################################
+
+# IMPLEMENTATION
+
+=head2 Useful functions
+
+Here are a list of useful functions and helpers to define tests.
+
+=cut
+
+# list test number and description
+sub list_test {
+ my $i = 0;
+ for (@TESTS) {
+ my ($desc, $f, @args) = @$_;
+ printf "%2d.\t%s\n", $i++, $desc;
+ }
+}
+
+sub run_test {
+ if ($SUBUNIT) {
+ run_test_subunit(@_);
+ } else {
+ run_test_normal(@_);
+ }
+}
+
+sub run_test_normal {
+ for (@_) {
+ my ($desc, $f, @args) = @$_;
+ my $err;
+
+ reset_env();
+ say "TEST: $desc";
+ if ($VERBOSE) {
+ $err = $f->(@args);
+ } else {
+ # turn off STDOUT
+ open my $saveout, ">&STDOUT";
+ open STDOUT, '>', File::Spec->devnull();
+ $err = $f->(@args);
+ open STDOUT, ">&", $saveout;
+ }
+ print_res($err);
+ print "\n";
+ }
+ reset_env();
+}
+
+sub run_test_subunit {
+ for (@_) {
+ my ($desc, $f, @args) = @$_;
+ my $err;
+ my $str = '';
+
+ reset_env();
+ say "test: $desc";
+
+ # capture output in $buf
+ my $buf = '';
+ open my $handle, '>', \$buf;
+ select $handle;
+
+ # check for die() calls
+ eval {
+ $err = $f->(@args);
+ };
+ if ($@) {
+ $str = $@;
+ $err = 1;
+ }
+ close $handle;
+
+ # restore output
+ select STDOUT;
+
+ # result string is output + eventual exception message
+ $str = $buf.$str;
+
+ printf "%s: %s [\n%s]\n", ($err > 0 ? "failure" : "success"), $desc, $str;
+ }
+ reset_env();
+}
+
+sub parse_test_string {
+ my $s = shift;
+ my @tests = ();
+
+ if (!length($s)) {
+ return ();
+ }
+
+ for (split /,/, $s) {
+ if (/^\d+$/) {
+ if ($_ >= @TESTS) {
+ return ();
+ }
+ push @tests, $TESTS[$_];
+ }
+ elsif (/^(\d+)-(\d+)$/) {
+ my ($min, $max) = sort ($1, $2);
+ if ($max >= @TESTS) {
+ return ();
+ }
+
+ for ($min..$max) {
+ push @tests, $TESTS[$_];
+ }
+ }
+ else {
+ return ();
+ }
+ }
+
+ return @tests;
+}
+
+sub print_res {
+ my $err = shift;
+ if ($err) {
+ printf " RES: %s%d ERR%s\n", color('bold red'), $err, color 'reset';
+ } else {
+ printf " RES: %sOK%s\n", color('bold green'), color 'reset';
+ }
+}
+
+sub make_env {
+ my ($exts, $dirs) = @_;
+ my @all;
+ my $nb = 0;
+ for my $dir (@$dirs) {
+ for (@$exts) {
+ my $fn = $dir . "file$nb." . $_;
+ my $f = File->new_remote($fn, 'ABSPATH');
+ $f->delete_on_destruction(1);
+ push @all, $f;
+ $nb++;
+ }
+ }
+
+ @all;
+}
+
+=head3 C<combine ( \@set, $n )>
+
+=head3 C<combine ( ['a', 'b', 'c'], 2 )>
+
+Return a list of all possible I<n>-uplet (or combination of C<$n> element) of C<@set>.
+
+=cut
+sub combine {
+ my ($list, $n) = @_;
+ die "Insufficient list members" if $n > @$list;
+
+ return map [$_], @$list if $n <= 1;
+
+ my @comb;
+
+ for (my $i = 0; $i+$n <= @$list; $i++) {
+ my $val = $list->[$i];
+ my @rest = @$list[$i+1..$#$list];
+ push @comb, [$val, @$_] for combine(\@rest, $n-1);
+ }
+
+ return @comb;
+}
+
+
+=head3 C<reset_remote( )>
+
+Remove all files in the server C<$DIR> (not root)
+
+=cut
+sub reset_remote {
+ # remove_tree($LOCALPATH . '/'. $DIR);
+ # make_path($LOCALPATH . '/'. $DIR);
+ my $DIR;
+ my @names;
+ my $name;
+
+ smb_client_cmd(0, '-c', "deltree ./*");
+
+ # Ensure all files are gone.
+
+ opendir(DIR,$LOCALPATH) or die "Can't open $LOCALPATH\n";
+ @names = readdir(DIR) or die "Unable to read $LOCALPATH\n";
+ closedir(DIR);
+ foreach $name (@names) {
+ next if ($name eq "."); # skip the current directory entry
+ next if ($name eq ".."); # skip the parent directory entry
+ die "$LOCALPATH not empty\n";
+ }
+}
+
+=head3 C<reset_tmp( )>
+
+Remove all files in the temp directory C<$TMP>
+
+=cut
+sub reset_tmp {
+ remove_tree($TMP, { keep_root => 1 });
+}
+
+
+=head3 C<reset_env( )>
+
+Remove both temp and remote (C<$DIR>) files
+
+=cut
+sub reset_env {
+ reset_tmp();
+ reset_remote();
+}
+
+=head3 C<file_list ( @files )>
+
+Make a multiline string of all the files remote path, one path per line.
+
+C<@files> must be a list of C<File> instance.
+
+=cut
+sub file_list {
+ my @files = @_;
+ my $s = '';
+ for (@files) {
+ $s .= $_->remotepath."\n";
+ }
+ return $s;
+}
+
+# remove leading "./"
+sub remove_dot {
+ my $s = shift;
+ $s =~ s{^\./}{};
+ $s;
+}
+
+=head3 C<check_remote( $remotepath, \@files )>
+
+Check if C<$remotepath> has B<exactly> all the C<@files>.
+
+Print a summary on STDOUT.
+
+C<@files> must be a list of C<File> instance.
+
+=cut
+sub check_remote {
+ my ($subpath, $files) = @_;
+ my (%done, %expected);
+ my (@less, @more, @diff);
+
+ for (@$files) {
+ my $fn = remove_dot($_->remotepath);
+ $expected{$fn} = $_;
+ $done{$fn} = 0;
+ }
+
+ my %remote;
+ File::walk(sub { $remote{remove_dot($_->remotepath)} = $_ }, File::tree($subpath));
+
+ for my $rfile (sort keys %remote) {
+
+ # files that shouldn't be there
+ if (!exists $expected{$rfile}) {
+ say " + $rfile";
+ push @more, $rfile;
+ next;
+ }
+
+ # same file multiple times
+ if ($done{$rfile} > 0) {
+ $done{$rfile}++;
+ push @more, $rfile;
+ printf " +%3d %s\n", $done{$rfile}, $rfile;
+ next;
+ }
+
+ $done{$rfile}++;
+
+ # different file
+ my $rmd5 = $remote{$rfile}->md5;
+ if ($expected{$rfile}->md5 ne $rmd5) {
+ say " ! $rfile ($rmd5)";
+ push @diff, $rfile;
+ next;
+ }
+
+ say " $rfile";
+ }
+
+ # file that should have been in tar
+ @less = grep { $done{$_} == 0 } sort keys %done;
+ for (@less) {
+ say " - $_";
+ }
+
+ # summary
+ printf("\t%d files, +%d, -%d, !%d\n",
+ scalar keys %done,
+ scalar @more,
+ scalar @less,
+ scalar @diff);
+ return (@more + @less + @diff); # nb of errors
+}
+
+=head3 C<check_tar( $path_to_tar, \@files )>
+
+Check if the archive C<$path_to_tar> has B<exactly> all the C<@files>.
+
+Print a summary on C<STDOUT>;
+
+C<@files> must be a list of C<File> instance.
+
+=cut
+sub check_tar {
+ my ($tar, $files) = @_;
+ my %done;
+ my (@less, @more, @diff);
+
+ my %h;
+
+
+ if (!-f $tar) {
+ say "no tar file $tar";
+ return 1;
+ }
+
+ for (@$files) {
+ $h{$_->tarpath} = $_;
+ $done{$_->tarpath} = 0;
+ }
+
+ my $total = 0;
+ my $i = Archive::Tar->iter($tar, 1, {md5 => 1});
+ while (my $f = $i->()) {
+ if ($f->has_content) {
+ my $p = $f->full_path;
+
+ # we skip pseudo files of Pax format archives
+ next if ($p =~ m/\/PaxHeader/);
+
+ $total++;
+ $p =~ s{^\./+}{};
+
+ # file that shouldn't be there
+ if (!exists $done{$p}) {
+ push @more, $p;
+ say " + $p";
+ next;
+ }
+
+ # same file multiple times
+ if ($done{$p} > 0) {
+ $done{$p}++;
+ push @more, $p;
+ printf " +%3d %s\n", $done{$p}, $p;
+ next;
+ }
+
+ $done{$p}++;
+
+ # different file
+
+ my $md5 = $f->data;
+ if ($^V lt v5.16) {
+ $md5 = md5_hex($md5);
+ }
+
+ if ($md5 ne $h{$p}->md5) {
+ say " ! $p ($md5)";
+ push @diff, $p;
+ next;
+ }
+
+ say " $p";
+ }
+ }
+
+ # file that should have been in tar
+ @less = grep { $done{$_} == 0 } keys %done;
+ for (sort @less) {
+ say " - $_";
+ }
+
+ # summary
+ printf("\t%d files, +%d, -%d, !%d\n",
+ $total,
+ scalar @more,
+ scalar @less,
+ scalar @diff);
+ return (@more + @less + @diff); # nb of errors
+}
+
+=head3 C<smb_client_cmd( $will_die, @args)>
+
+=head3 C<smb_client_cmd( 0, '-c', 'deltree', $somedir )>
+
+Run smbclient with C<@args> passed as argument and return output.
+
+Each element of C<@args> becomes one escaped argument of smbclient.
+
+Host, share, user, password and the additional arguments provided on
+the command-line are already inserted.
+
+The output contains both the C<STDOUT> and C<STDERR>.
+
+if C<$will_die> then Die if smbclient crashes or exits with an error code.
+otherwise return output
+
+=cut
+sub smb_client_cmd {
+ my ($will_die, @args) = @_;
+
+ my $fullpath = "//$HOST/$SHARE";
+ my $cmd = sprintf("%s %s %s",
+ quotemeta($BIN),
+ quotemeta($fullpath),
+ join(' ', map {quotemeta} (@SMBARGS, @args)));
+
+ if ($DEBUG) {
+ my $tmp = $cmd;
+ $tmp =~ s{\\([./+-])}{$1}g;
+ say color('bold yellow'), $tmp, color('reset');
+ }
+
+ my $out = `$cmd 2>&1`;
+ my $err = $?;
+ my $errstr = '';
+ # handle abnormal exit
+ if ($err == -1) {
+ $errstr = "failed to execute $cmd: $!\n";
+ }
+ elsif ($err & 127) {
+ $errstr = sprintf "child died with signal %d (%s)\n", ($err & 127), $cmd;
+ }
+ elsif ($err >> 8) {
+ $errstr = sprintf "child exited with value %d (%s)\n", ($err >> 8), $cmd;
+ }
+
+ if ($DEBUG) {
+ say $out;
+ }
+
+ if ($err) {
+ if ($will_die) {
+ die "ERROR: $errstr";
+ } else {
+ say "ERROR: $errstr";
+ }
+ }
+ return $out;
+}
+
+=head3 C<smb_client ( @args )>
+
+Run smbclient with C<@args> passed as argument and return output.
+
+Each element of C<@args> becomes one escaped argument of smbclient.
+
+Host, share, user, password and the additional arguments provided on
+the command-line are already inserted.
+
+The output contains both the C<STDOUT> and C<STDERR>.
+
+Die if smbclient crashes or exits with an error code.
+
+=cut
+sub smb_client {
+ my (@args) = @_;
+ return smb_client_cmd(1, @args)
+}
+
+sub smb_cmd {
+ return smb_client('-c', join(' ', @_));
+}
+
+=head3 C<smb_tar( $cmd, @args )>
+
+=head3 C<smb_tar( 'tarmode inc', '-Tc', $TAR, $DIR )>
+
+Run C<$cmd> command and use C<@args> as argument and return output.
+
+Wrapper around C<smb_client> for tar calls.
+
+=cut
+sub smb_tar {
+ my ($cmd, @rest) = @_;
+ printf " CMD: %s\n ARG: %s\n", $cmd, join(' ', @rest);
+ smb_client((length($cmd) ? ('-c', $cmd) : ()), @rest);
+}
+
+=head3 C<random( $min, $max )>
+
+Return integer in C<[ $min ; $max ]>
+
+=cut
+sub random {
+ my ($min, $max) = @_;
+ ($min, $max) = ($max, $min) if ($min > $max);
+ $min + int(rand($max - $min));
+}
+
+#################################
+
+package File;
+
+=head2 The File module
+
+All the test should use the C<File> class. It has nice functions and
+methods to deal with paths, to create random files, to list the
+content of the server, to change attributes, etc.
+
+There are 2 kinds of C<File>: remote and local.
+
+=over
+
+=item * Remote files are accessible on the server.
+
+=item * Local files are not.
+
+=back
+
+Thus, some methods only works on remote files. If they do not make
+sense for local ones, they always return undef.
+
+=cut
+use File::Basename;
+use File::Path qw/make_path remove_tree/;
+use Digest::MD5 qw/md5_hex/;
+use Scalar::Util 'blessed';
+
+=head3 Constructors
+
+=head4 C<< File->new_remote($path [, $abs, $size]) >>
+
+Creates a file accessible on the server at C<$DIR/$path> ie. not at the
+root of the share and write C<$size> random bytes.
+
+If no size is provided, a random size is chosen.
+
+If you want to remove the automatic prefix C<$DIR>, set C<$abs> to 1.
+
+The file is created without any DOS attributes.
+
+If C<$path> contains non-existent directories, they are automatically
+created.
+
+=cut
+sub new_remote {
+ my ($class, $path, $abs, $size) = @_;
+ my ($file, $dir) = fileparse($path);
+
+ $dir = '' if $dir eq './';
+ my $loc;
+
+ if ($abs) {
+ $loc = cleanpath($main::LOCALPATH.'/'.$dir);
+ } else {
+ $dir = cleanpath($main::DIR.'/'.$dir);
+ $loc = cleanpath($main::LOCALPATH.'/'.$dir);
+ }
+
+ make_path($loc);
+
+ my $self = bless {
+ 'attr' => {qw/r 0 s 0 h 0 a 0 d 0 n 0/},
+ 'dir' => $dir,
+ 'name' => $file,
+ 'md5' => create_file($loc.'/'.$file, $size),
+ 'remote' => 1,
+ }, $class;
+
+ $self->set_attr();
+
+ $self;
+}
+
+=head4 C<< File->new_local($abs_path [, $data]) >>
+
+Creates a file at C<$abs_path> with $data in it on the system.
+If $data is not provided, fill it with random bytes.
+
+=cut
+sub new_local {
+ my ($class, $path, $data) = @_;
+ my ($file, $dir) = fileparse($path);
+
+ make_path($dir);
+
+ my $md5;
+
+ if (defined $data) {
+ open my $f, '>', $path or die "can't write in $path: $!";
+ print $f $data;
+ close $f;
+ $md5 = md5_hex($data);
+ } else {
+ $md5 = create_file($path);
+ }
+
+ my $self = {
+ 'attr' => {qw/r 0 s 0 h 0 a 0 d 0 n 0/},
+ 'dir' => $dir,
+ 'name' => $file,
+ 'md5' => $md5,
+ 'remote' => 0,
+ };
+
+ bless $self, $class;
+}
+
+=head3 Methods
+
+=head4 C<< $f->localpath >>
+
+Return path on the system eg. F</opt/samba/share/test_tar_mode/file>
+
+=cut
+sub localpath {
+ my $s = shift;
+ if ($s->{remote}) {
+ return cleanpath($main::LOCALPATH.'/'.$s->remotepath);
+ }
+ else {
+ return cleanpath($s->{dir}.'/'.$s->{name});
+ }
+}
+
+=head4 C<< $f->remotepath >>
+
+Return path on the server share.
+
+Return C<undef> if the file is local.
+
+=cut
+sub remotepath {
+ my ($s) = @_;
+ return undef if !$s->{remote};
+ my $r = $s->{dir}.'/'.$s->{name};
+ $r =~ s{^/}{};
+ return cleanpath($r);
+}
+
+
+=head4 C<< $f->remotedir >>
+
+Return the directory path of the file on the server.
+
+Like C<< $f->remotepath >> but without the final file name.
+
+=cut
+sub remotedir {
+ my $s = shift;
+ return undef if !$s->{remote};
+ cleanpath($s->{dir});
+}
+
+=head4 C<< $f->tarpath >>
+
+Return path as it would appear in a tar archive.
+
+Like C<< $f->remotepath >> but prefixed with F<./>
+
+=cut
+sub tarpath {
+ my $s = shift;
+ return undef if !$s->{remote};
+ my $r = $s->remotepath;
+ $r =~ s{^\./+}{};
+ return $r;
+}
+
+=head4 C<< $f->delete_on_destruction( 0 ) >>
+
+=head4 C<< $f->delete_on_destruction( 1 ) >>
+
+By default, a C<File> is not deleted on the filesystem when it is not
+referenced anymore in Perl memory.
+
+When set to 1, the destructor unlink the file if it is not already removed.
+If the C<File> created directories when constructed, it does not remove them.
+
+=cut
+sub delete_on_destruction {
+ my ($s, $delete) = @_;
+ $s->{delete_on_destruction} = $delete;
+}
+
+=head4 C<< $f->set_attr( ) >>
+
+=head4 C<< $f->set_attr( 'a' ) >>
+
+=head4 C<< $f->set_attr( 'a', 'r', 's', 'h' ) >>
+
+Remove all DOS attributes and only set the one provided.
+
+=cut
+sub set_attr {
+ my ($s, @flags) = @_;
+ return undef if !$s->{remote};
+
+ $s->{attr} = {qw/r 0 s 0 h 0 a 0 d 0 n 0/};
+
+ for (@flags) {
+ $s->{attr}{lc($_)} = 1;
+ }
+
+ my $file = $s->{name};
+ my @args;
+ if ($s->remotedir) {
+ push @args, '-D', $s->remotedir;
+ }
+ main::smb_client(@args, '-c', qq{setmode "$file" -rsha});
+ if (@flags && $flags[0] !~ /n/i) {
+ main::smb_client(@args, '-c', qq{setmode "$file" +}.join('', @flags));
+ }
+}
+
+=head4 C<< $f->attr_any( 'a' ) >>
+
+=head4 C<< $f->attr_any( 'a', 's', ... ) >>
+
+Return 1 if the file has any of the DOS attributes provided.
+
+=cut
+sub attr_any {
+ my ($s, @flags) = @_;
+ for (@flags) {
+ return 1 if $s->{attr}{$_};
+ }
+ 0;
+}
+
+
+=head4 C<< $f->attr( 'a' ) >>
+
+=head4 C<< $f->attr( 'a', 's', ... ) >>
+
+Return 1 if the file has all the DOS attributes provided.
+
+=cut
+sub attr {
+ my ($s, @flags) = @_;
+ for (@flags) {
+ return 0 if !$s->{attr}{$_};
+ }
+ 1;
+}
+
+=head4 C<< $f->attr_str >>
+
+Return DOS attributes as a compact string.
+
+ Read-only, hidden, system, archive => "rhsa"
+
+=cut
+sub attr_str {
+ my $s = shift;
+ return undef if !$s->{remote};
+ join('', map {$_ if $s->{attr}{$_}} qw/r h s a d n/);
+}
+
+=head4 C<< $f->set_time($t) >>
+
+Set modification and access time of the file to C<$t>.
+
+C<$t> must be in Epoch time (number of seconds since 1970/1/1).
+
+=cut
+sub set_time {
+ my ($s, $t) = @_;
+ utime $t, $t, $s->localpath;
+}
+
+=head4 C<< $f->md5 >>
+
+Return md5 sum of the file.
+
+The result is cached.
+
+=cut
+sub md5 {
+ my $s = shift;
+
+ if (!$s->{md5}) {
+ open my $h, '<', $s->localpath() or die "can't read ".$s->localpath.": $!";
+ binmode $h;
+ $s->{md5} = Digest::MD5->new->addfile($h)->hexdigest;
+ close $h;
+ }
+
+ return $s->{md5};
+}
+
+sub DESTROY {
+ my $s = shift;
+ if ($s->{delete_on_destruction} && -f $s->localpath) {
+ if ($main::DEBUG) {
+ say "DESTROY ".$s->localpath;
+ }
+ unlink $s->localpath;
+ }
+}
+
+=head3 Functions
+
+=head4 C<< File::walk( \&function, @files) >>
+
+=head4 C<< File::walk( sub { ... }, @files) >>
+
+Iterate on file hierarchy in C<@files> and return accumulated results.
+
+Use C<$_> in the sub to access the current C<File>.
+
+The C<@files> must come from a call to the C<File::tree> function.
+
+=cut
+sub walk {
+ my $fun = \&{shift @_};
+
+ my @res;
+
+ for (@_) {
+ if ($_->{attr}{d}) {
+ push @res, walk($fun, @{$_->{content}});
+ } else {
+ push @res, $fun->($_);
+ }
+ }
+
+ return @res;
+}
+
+=head4 C<< File::list( $remotepath ) >>
+
+Return list of file (C<File> instance) in C<$remotepath>.
+
+C<$remotepath> must be a directory.
+
+=cut
+sub list {
+ my ($path) = @_;
+ $path ||= '/';
+ my @files;
+ my $out = main::smb_client('-D', $path, '-c', 'ls');
+ $path =~ s{^/}{};
+
+ for (split /\n/, $out) {
+ next if !/^ (.+?)\s+([AHSRDN]*)\s+(\d+)\s+(.+)/o;
+ my ($fn, $attr, $size, $date) = ($1, $2, $3, $4);
+ next if $fn =~ /^\.{1,2}$/;
+
+ push @files, bless {
+ 'remote' => 1,
+ 'dir' => $path,
+ 'name' => $fn,
+ 'size' => int($size),
+ 'date' => $date,
+ 'attr' => {
+ # list context returns something different than the
+ # boolean matching result => force scalar context
+ 'a' => scalar ($attr =~ /A/),
+ 'h' => scalar ($attr =~ /H/),
+ 's' => scalar ($attr =~ /S/),
+ 'r' => scalar ($attr =~ /R/),
+ 'd' => scalar ($attr =~ /D/),
+ 'n' => scalar ($attr =~ /N/),
+ },
+ }, 'File';
+ }
+ return @files;
+}
+
+=head4 C<< File::tree( $remotepath ) >>
+
+Return recursive list of file in C<$remotepath>.
+
+C<$remotepath> must be a directory.
+
+Use C<File::walk()> to iterate over all the files.
+
+=cut
+sub tree {
+ my ($d) = @_;
+ my @files;
+
+ if (!defined $d) {
+ @files = list();
+ } elsif (blessed $d) {
+ @files = list($d->remotepath);
+ } else {
+ @files = list($d);
+ }
+
+ for my $f (@files) {
+ if ($f->{attr}{d}) {
+ $f->{content} = [tree($f)];
+ }
+ }
+
+ return @files;
+}
+
+# remove trailing or duplicated slash
+sub cleanpath {
+ my $p = shift;
+ $p =~ s{/+}{/}g;
+ $p =~ s{/$}{};
+ $p;
+}
+
+# create random file at path local path $fn
+sub create_file {
+ my ($fn, $size) = @_;
+ my $buf = '';
+ unlink $fn if -e $fn;
+ $size ||= main::random(512, 1024);
+ $size = int($size);
+ my $md5;
+
+ # try /dev/urandom, faster
+ if (-e '/dev/urandom') {
+ my $cmd = sprintf('head -c %d /dev/urandom | tee %s | md5sum',
+ $size, quotemeta($fn));
+ $md5 = (split / /, `$cmd`)[0];
+ } else {
+ open my $out, '>', $fn or die "can't open $fn: $!\n";
+ binmode $out;
+ for (1..$size) {
+ $buf .= pack('C', main::random(0, 256));
+ }
+ print $out $buf;
+ close $out;
+ $md5 = md5_hex($buf);
+ }
+ return $md5;
+}
+
+
+=head3 Examples
+
+ # create remote file in $DIR/foo/bar
+ my $f = File->new_remote("foo/bar/myfile");
+ say $f->localpath; # /opt/share/$DIR/foo/bar/myfile
+ say $f->remotepath; # $DIR/foo/bar/myfile
+ say $f->remotedir; # $DIR/foo/bar
+
+
+ # same but in root dir
+ my $f = File->new_remote("myfile", 1);
+ say $f->localpath; # /opt/share/myfile
+ say $f->remotepath; # myfile
+ say $f->remotedir; #
+
+
+ # create local random temp file in $TMP
+ my $f = File->new_local("$TMP/temp");
+ say $f->remotepath; # undef because it's not on the server
+
+
+ # same but file contains "hello"
+ my $f = File->new_local("$TMP/temp", "hello");
+
+
+ # list of files in $DIR (1 level)
+ for (File::list($DIR)) {
+ say $_->remotepath;
+ }
+
+
+ # list of all files in dir and subdir of $DIR
+ File::walk(sub { say $_->remotepath }, File::tree($DIR));
+
+=cut
+
+1;
diff --git a/source3/script/tests/test_smbclient_tarmode.sh b/source3/script/tests/test_smbclient_tarmode.sh
new file mode 100755
index 0000000..d48e412
--- /dev/null
+++ b/source3/script/tests/test_smbclient_tarmode.sh
@@ -0,0 +1,197 @@
+#!/bin/sh
+
+# this runs a simple tarmode test
+
+if [ $# -lt 7 ]; then
+ cat <<EOF
+Usage: test_smbclient_tarmode.sh SERVER SERVER_IP USERNAME PASSWORD LOCAL_PATH PREFIX SMBCLIENT [create|extract] <smbclient arguments>
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+SERVER_IP="$2"
+USERNAME="$3"
+PASSWORD="$4"
+LOCAL_PATH="$5"
+PREFIX="$6"
+SMBCLIENT="$7"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+shift 7
+ADDARGS="$*"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+FAILCOUNT=0
+
+# Check command is available
+have_command()
+{
+ type "$1" >/dev/null 2>&1
+ return $?
+}
+
+# Create a test corpus
+create_test_data()
+{
+
+ local DIR="$1"
+ local BS=1024
+ local NUM_FILES=10
+ local NORND_COUNT=25
+
+ # Bomb if dir exists
+ if [ -e "$DIR" ]; then
+ echo "Test data directory '$DIR' already exists!"
+ false
+ return
+ fi
+
+ if ! mkdir -p "$DIR" >/dev/null 2>&1; then
+ echo "Couldn't create test data directory '$DIR'"
+ false
+ return
+ fi
+
+ local I=1
+ if have_command "od"; then # Use random file sizes
+ local RND_COUNT
+ for RND_COUNT in $(od -An -N$NUM_FILES -tu1 </dev/urandom); do
+ if ! dd if=/dev/urandom of="$DIR/file.$I" bs=$BS count=$RND_COUNT >/dev/null 2>&1; then
+ echo "Couldn't create test file '$DIR/file.$I' (random size)"
+ false
+ return
+ fi
+ I=$(expr $I + 1)
+ done
+ else # Fallback to same file sizes
+ while [ $I -le $NUM_FILES ]; do
+ if ! dd if=/dev/urandom of="$DIR/file.$I" bs=$BS count=$NORND_COUNT >/dev/null 2>&1; then
+ echo "Couldn't create test file '$DIR/file.$I' (static size)"
+ false
+ return
+ fi
+ I=$(expr $I + 1)
+ done
+ fi
+
+ true
+ return
+
+}
+
+# Check that two directories are equivalent (In Data content)
+validate_data()
+{
+ local DIR1="$1"
+ local DIR2="$2"
+
+ diff -r "$DIR1" "$DIR2"
+ return $?
+}
+
+# Test tarmode -Tc
+test_tarmode_creation()
+{
+
+ # Clear temp data
+ rm -rf -- "$PREFIX"/tarmode >/dev/null 2>&1
+ rm -f "$PREFIX"/tarmode.tar >/dev/null 2>&1
+ $SMBCLIENT //$SERVER/tarmode $CONFIGURATION -U$USERNAME%$PASSWORD -c "deltree smbclient_tar"
+
+ # Build the test data
+ if ! create_test_data "$LOCAL_PATH"; then
+ echo "Test data creation failed"
+ false
+ return
+ fi
+
+ # Create tarfile with smbclient
+ if ! $SMBCLIENT //$SERVER/tarmode $CONFIGURATION -U$USERNAME%$PASSWORD -I $SERVER_IP -p 139 \
+ $ADDARGS -c "tarmode full" -Tc "$PREFIX/tarmode.tar" "/smbclient_tar"; then
+ echo "Couldn't create tar file with tarmode -Tc"
+ false
+ return
+ fi
+
+ # Extract data to verify - this puts it into $PREFIX/smbclient_tar/
+ # but we must leave it there as it's used to verify in test_tarmode_extraction()
+ if ! tar -xf "$PREFIX/tarmode.tar" -C "$PREFIX"; then
+ echo "Couldn't extract data from created tarfile"
+ false
+ return
+ fi
+
+ # Verify data
+ if ! validate_data "$PREFIX/smbclient_tar" "$LOCAL_PATH"; then
+ echo "Data not equivalent"
+ false
+ return
+ fi
+
+ # Clear temp data
+ rm -rf -- "$PREFIX"/tarmode >/dev/null 2>&1
+ rm -f "$PREFIX"/tarmode.tar >/dev/null 2>&1
+ $SMBCLIENT //$SERVER/tarmode $CONFIGURATION -U$USERNAME%$PASSWORD -c "deltree smbclient_tar"
+ true
+ return
+
+}
+
+# Test tarmode -Tx
+test_tarmode_extraction()
+{
+
+ # Clear temp data
+ rm -rf -- "$PREFIX"/tarmode >/dev/null 2>&1
+ rm -f "$PREFIX"/tarmode.tar >/dev/null 2>&1
+ $SMBCLIENT //$SERVER/tarmode $CONFIGURATION -U$USERNAME%$PASSWORD -c "deltree smbclient_tar"
+
+ # Build the test data
+ if ! create_test_data "$PREFIX/tarmode"; then
+ echo "Test data creation failed"
+ false
+ return
+ fi
+
+ # Create tarfile to extract on client
+ if ! tar -cf "$PREFIX/tarmode.tar" -C "$PREFIX" smbclient_tar; then
+ echo "Couldn't create tar archive"
+ false
+ return
+ fi
+
+ # Extract tarfile with smbclient
+ if ! $SMBCLIENT //$SERVER/tarmode $CONFIGURATION -U$USERNAME%$PASSWORD -I $SERVER_IP -p 139 \
+ $ADDARGS -c "tarmode full" -Tx "$PREFIX/tarmode.tar"; then
+ echo "Couldn't extract tar file with tarmode -Tx"
+ false
+ return
+ fi
+
+ # Verify data
+ if ! validate_data "$PREFIX/smbclient_tar" "$LOCAL_PATH"; then
+ echo "Data not equivalent"
+ false
+ return
+ fi
+
+ # Clear temp data
+ rm -rf -- "$PREFIX"/tarmode >/dev/null 2>&1
+ rm -f "$PREFIX"/tarmode.tar >/dev/null 2>&1
+ $SMBCLIENT //$SERVER/tarmode $CONFIGURATION -U$USERNAME%$PASSWORD -c "deltree smbclient_tar"
+ # Cleanup the verification data created by test_tarmode_creation().
+ rm -rf "$PREFIX"/smbclient_tar >/dev/null 2>&1
+ true
+ return
+
+}
+
+testit "test_tarmode_creation" \
+ test_tarmode_creation || FAILCOUNT=$(expr $FAILCOUNT + 1)
+
+testit "test_tarmode_extraction" \
+ test_tarmode_extraction || FAILCOUNT=$(expr $FAILCOUNT + 1)
+
+testok $0 $FAILCOUNT
diff --git a/source3/script/tests/test_smbcquota.py b/source3/script/tests/test_smbcquota.py
new file mode 100755
index 0000000..02229d7
--- /dev/null
+++ b/source3/script/tests/test_smbcquota.py
@@ -0,0 +1,244 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Tests for smbcquotas
+# Copyright (C) Noel Power 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 os, subprocess, sys
+import traceback
+import logging
+import shutil
+
+USER_QUOTAS = 1
+USER_DEFAULT_QUOTAS = 2
+GROUP_QUOTAS = 3
+GROUP_DEFAULT_QUOTAS = 4
+BLOCK_SIZE = 1024
+DEFAULT_SOFTLIM = 2
+DEFAULT_HARDLIM = 4
+
+class test_env:
+ def __init__(self):
+ self.server = None
+ self.domain = None
+ self.username = None
+ self.password = None
+ self.envdir = None
+ self.quota_db = None
+ self.smbcquotas = None
+ self.users = []
+
+class user_info:
+ def __init__(self):
+ self.uid = 0
+ self.username = ""
+ self.softlim = 0
+ self.hardlim = 0
+
+class Quota:
+ def __init__(self):
+ self.flags = 0
+ self.quotatype = USER_DEFAULT_QUOTAS
+ self.uid = 0
+ self.usedblocks = 0
+ self.softlimit = 0
+ self.hardlimit = 0
+ self.hardlimit = 0
+ self.usedinodes = 0
+ self.slimitinodes = 0
+ self.hlimitinodes = 0
+
+def init_quota_db(users, output_file):
+ filecontents = open(output_file,"w+")
+ lines = ""
+ default_values = "0 " + str(DEFAULT_SOFTLIM) + " " + str(DEFAULT_HARDLIM) + " 0 0 0"
+ for user in users:
+ lines = lines + user.uid + " " + default_values + "\n"
+ filecontents.write(lines)
+ filecontents.close()
+
+def load_quotas(input_file):
+ fileContents = open(input_file,"r")
+ lineno = 0
+ quotas = []
+ for line in fileContents:
+ if line.strip().startswith("#"):
+ continue
+ content = line.strip().split()
+ quota = Quota()
+ if len(content) < 7:
+ logging.debug("ignoring line %d, doesn't have enough fields\n"%lineno)
+ else:
+ quota.flags = 2
+ quota.uid = content[0]
+ quota.usedblocks = content[1]
+ quota.softlimit = content[2]
+ quota.hardlimit = content[3]
+ quota.usedinodes = content[4]
+ quota.slimitinodes = content[5]
+ quota.hlimitinodes = content[6]
+ quotas.append(quota)
+
+ fileContents.close()
+ return quotas
+
+def get_quotas(uid, quota_list):
+ for quota in quota_list:
+ if quota.uid == uid:
+ return quota
+ return None
+
+def get_users():
+ output = subprocess.Popen(['getent', 'passwd'],
+ stdout=subprocess.PIPE).communicate()[0].decode("utf-8").split('\n')
+ users = []
+ for line in output:
+ info = line.split(':')
+ if len(info) > 3 and info[0]:
+ user = user_info()
+ user.username = info[0]
+ user.uid = info[2]
+ logging.debug("Adding user ->%s<-\n"%user.username)
+ users.append(user)
+ return users
+
+
+
+def smbcquota_output_to_userinfo(output):
+ infos = []
+ for line in output:
+ if len(line) > 1:
+ username = line.strip(':').split()[0]
+ quota_info = line.split(':')[1].split('/')
+ if len(quota_info) > 2:
+ info = user_info()
+ info.username = username.strip()
+ info.softlim = int(quota_info[1].strip()) / BLOCK_SIZE
+ info.hardlim = int(quota_info[2].strip()) / BLOCK_SIZE
+ infos.append(info)
+ return infos
+
+def check_quota_limits(infos, softlim, hardlim):
+ if len(infos) < 1:
+ logging.debug("no users info to check :-(\n")
+ return False
+ for info in infos:
+ if int(info.softlim) != softlim:
+ logging.debug("expected softlimit %s got ->%s<-\n"%(softlim, info.softlim))
+ return False
+ if int(info.hardlim) != hardlim:
+ logging.debug("expected hardlimit limit %s got %s\n"%(hardlim,info.hardlim))
+ return False
+ return True
+
+class test_base:
+ def __init__(self, env):
+ self.env = env
+ def run(self, protocol):
+ pass
+
+class listtest(test_base):
+ def run(self, protocol):
+ init_quota_db(self.env.users, self.env.quota_db)
+ quotas = load_quotas(self.env.quota_db)
+ args = [self.env.smbcquotas]
+ remaining_args = ['-U' + self.env.username + "%" + self.env.password, '-L', '//' + self.env.server + '/quotadir']
+ if protocol == 'smb2':
+ args.append('-m smb2')
+ args.extend(remaining_args)
+ output = subprocess.Popen([self.env.smbcquotas, '-U' + self.env.username + "%" + self.env.password, '-L', '//' + self.env.server + '/quotadir'], stdout=subprocess.PIPE).communicate()[0].decode("utf-8").split('\n')
+ infos = smbcquota_output_to_userinfo(output)
+ return check_quota_limits(infos, DEFAULT_SOFTLIM, DEFAULT_HARDLIM)
+def get_uid(name, users):
+ for user in users:
+ if user.username == name:
+ return user.uid
+ return None
+
+class gettest(test_base):
+ def run(self, protocol):
+ init_quota_db(self.env.users, self.env.quota_db)
+ quotas = load_quotas(self.env.quota_db)
+ uid = get_uid(self.env.username, self.env.users)
+ output = subprocess.Popen([self.env.smbcquotas, '-U' + self.env.username + "%" + self.env.password, '-u' + self.env.username, '//' + self.env.server + '/quotadir'], stdout=subprocess.PIPE).communicate()[0].decode("utf-8").split('\n')
+ user_infos = smbcquota_output_to_userinfo(output)
+ db_user_info = get_quotas(uid, quotas)
+ # double check, we compare the results from the db file
+ # the quota script the server uses compared to what
+ # smbcquota is telling us
+ return check_quota_limits(user_infos, int(db_user_info.softlimit), int(db_user_info.hardlimit))
+
+class settest(test_base):
+ def run(self, protocol):
+ init_quota_db(self.env.users, self.env.quota_db)
+ quotas = load_quotas(self.env.quota_db)
+ uid = get_uid(self.env.username, self.env.users)
+ old_db_user_info = get_quotas(uid, quotas)
+
+ #increase limits by 2 blocks
+ new_soft_limit = (int(old_db_user_info.softlimit) + 2) * BLOCK_SIZE
+ new_hard_limit = (int(old_db_user_info.hardlimit) + 2) * BLOCK_SIZE
+
+ new_limits = "UQLIM:%s:%d/%d"%(self.env.username, new_soft_limit, new_hard_limit)
+ logging.debug("setting new limits %s"%new_limits)
+
+ output = subprocess.Popen([self.env.smbcquotas, '-U' + self.env.username + "%" + self.env.password, '//' + self.env.server + '/quotadir', '-S', new_limits], stdout=subprocess.PIPE).communicate()[0].decode("utf-8").split('\n')
+ logging.debug("output from smbcquota is %s"%output)
+ user_infos = smbcquota_output_to_userinfo(output)
+ return check_quota_limits(user_infos, new_soft_limit / BLOCK_SIZE, new_hard_limit / BLOCK_SIZE)
+
+# map of tests
+subtest_descriptions = {
+ "list test" : listtest,
+ "get test" : gettest,
+ "set test" : settest
+}
+
+def main():
+ logging.basicConfig(format='%(asctime)s %(message)s', level=logging.DEBUG)
+
+ logging.debug("got args %s\n"%str(sys.argv))
+
+ if len(sys.argv) < 7:
+ logging.debug ("Usage: test_smbcquota.py server domain username password envdir smbcquotas\n")
+ sys.exit(1)
+ env = test_env()
+ env.server = sys.argv[1]
+ env.domain = sys.argv[2]
+ env.username = sys.argv[3]
+ env.password = sys.argv[4]
+ env.envdir = sys.argv[5]
+ env.smbcquotas = sys.argv[6]
+ quota_script = os.path.join(os.path.dirname(sys.argv[0]),
+ "getset_quota.py")
+ #copy the quota script to the environment
+ shutil.copy2(quota_script, env.envdir)
+
+ env.quota_db = os.path.join(env.envdir, "quotas.db")
+ env.users = get_users()
+ for protocol in ['smb1', 'smb2']:
+ for key in subtest_descriptions.keys():
+ test = subtest_descriptions[key](env)
+ logging.debug("running subtest '%s' using protocol '%s'\n"%(key,protocol))
+ result = test.run(protocol)
+ if result == False:
+ logging.debug("subtest '%s' for '%s' failed\n"%(key,protocol))
+ sys.exit(1)
+ else:
+ logging.debug("subtest '%s' for '%s' passed\n"%(key,protocol))
+ sys.exit(0)
+
+if __name__ == '__main__':
+ main()
diff --git a/source3/script/tests/test_smbcquota.sh b/source3/script/tests/test_smbcquota.sh
new file mode 100755
index 0000000..c001192
--- /dev/null
+++ b/source3/script/tests/test_smbcquota.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+# Unix SMB/CIFS implementation.
+# Tests for smbcquotas
+# Copyright (C) Noel Power 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 test wrapper for smbcquota
+#
+if [ $# -lt 6 ]; then
+ cat <<EOF
+Usage: test_smbcquota.sh SERVER DOMAIN USERNAME PASSWORD LOCAL_PATH SMBCQUOTAS
+EOF
+ exit 1
+fi
+
+SERVER=$1
+DOMAIN=$2
+USERNAME=$3
+PASSWORD=$4
+ENVDIR=$(dirname $5)
+SMBCQUOTAS="$VALGRIND $6"
+shift 6
+
+TEST_SMBCQUOTAS=$(dirname $0)/test_smbcquota.py
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+testit "smbcquotas" ${TEST_SMBCQUOTAS} ${SERVER} ${DOMAIN} ${USERNAME} ${PASSWORD} ${ENVDIR} ${SMBCQUOTAS} || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_smbd_error.sh b/source3/script/tests/test_smbd_error.sh
new file mode 100755
index 0000000..d39b174
--- /dev/null
+++ b/source3/script/tests/test_smbd_error.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+#
+# Test smbd with failing chdir system call.
+#
+# Verify that smbd does not panic when the chdir system call is
+# returning an error. ensure that the output format for ACL entries
+#
+# Copyright (C) 2017 Christof Schmitt
+
+. $(dirname $0)/../../../testprogs/blackbox/subunit.sh
+failed=0
+
+if [ $SMBD_DONT_LOG_STDOUT -eq 1 ]; then
+ subunit_start_test "check_panic_0"
+ subunit_skip_test "check_panic_0" <<EOF
+logging to stdout disabled
+EOF
+
+ testok $0 $failed
+fi
+
+error_inject_conf=$(dirname $SMB_CONF_PATH)/error_inject.conf
+
+panic_count_0=$(grep -c PANIC $SMBD_TEST_LOG)
+
+#
+# Verify that a panic in smbd will result in a PANIC message in the log
+#
+
+# As a panic is expected here, also overwrite the default "panic
+# action" in selftest to not start a debugger
+echo 'error_inject:chdir = panic' >$error_inject_conf
+echo '[global]' >>$error_inject_conf
+echo 'panic action = ""' >>$error_inject_conf
+
+testit_expect_failure "smbclient" $VALGRIND \
+ $BINDIR/smbclient //$SERVER_IP/error_inject \
+ -U$USERNAME%$PASSWORD -c dir ||
+ failed=$(expr $failed + 1)
+
+rm $error_inject_conf
+
+panic_count_1=$(grep -c PANIC $SMBD_TEST_LOG)
+
+testit "check_panic_1" test $(expr $panic_count_0 + 1) -eq $panic_count_1 ||
+ failed=$(expr $failed + 1)
+
+#
+# Verify that a failing chdir vfs call does not result in a smbd panic
+#
+
+echo 'error_inject:chdir = ESTALE' >$error_inject_conf
+
+testit_expect_failure "smbclient" $VALGRIND \
+ $BINDIR/smbclient //$SERVER_IP/error_inject \
+ -U$USERNAME%$PASSWORD -c dir ||
+ failed=$(expr $failed + 1)
+
+panic_count_2=$(grep -c PANIC $SMBD_TEST_LOG)
+
+testit "check_panic_2" test $panic_count_1 -eq $panic_count_2 ||
+ failed=$(expr $failed + 1)
+
+rm $error_inject_conf
+
+testok $0 $failed
diff --git a/source3/script/tests/test_smbd_no_krb5.sh b/source3/script/tests/test_smbd_no_krb5.sh
new file mode 100755
index 0000000..faa46c9
--- /dev/null
+++ b/source3/script/tests/test_smbd_no_krb5.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+if [ $# -lt 1 ]; then
+ cat <<EOF
+Usage: test_smbd_no_krb5.sh SERVER USERNAME PASSWORD PREFIX
+EOF
+ exit 1
+fi
+
+smbclient=$1
+SERVER=$2
+USERNAME=$3
+PASSWORD=$4
+PREFIX=$5
+shift 5
+
+samba_bindir="$BINDIR"
+samba_kinit=kinit
+if test -x ${samba_bindir}/samba4kinit; then
+ samba_kinit=${samba_bindir}/samba4kinit
+fi
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+. $incdir/common_test_fns.inc
+
+failed=0
+
+opt="--option=gensec:gse_krb5=yes -U${USERNAME}%${PASSWORD}"
+
+# check kerberos access
+test_smbclient "test_krb5" "ls" "//$SERVER/tmp" $opt --use-kerberos=required || failed=$(expr $failed + 1)
+
+# disable krb5 globally so smbd won't accept it
+global_inject_conf=$(dirname $SMB_CONF_PATH)/global_inject.conf
+echo 'gensec:gse_krb5=no' >$global_inject_conf
+
+# verify that kerberos fails
+test_smbclient_expect_failure "smbd_no_krb5" "ls" "//$SERVER/tmp" --use-kerberos=required $opt || failed=$(expr $failed + 1)
+
+# verify downgrade to ntlmssp
+test_smbclient "test_spnego_downgrade" "ls" "//$SERVER/tmp" $opt --use-kerberos=disabled || failed=$(expr $failed + 1)
+
+echo '' >$global_inject_conf
+
+testok $0 $failed
diff --git a/source3/script/tests/test_smbget.sh b/source3/script/tests/test_smbget.sh
new file mode 100755
index 0000000..acc492d
--- /dev/null
+++ b/source3/script/tests/test_smbget.sh
@@ -0,0 +1,619 @@
+#!/usr/bin/env bash
+#
+# Blackbox test for smbget.
+#
+
+if [ $# -lt 8 ]; then
+ cat <<EOF
+Usage: test_smbget SERVER SERVER_IP DOMAIN REALM USERNAME PASSWORD WORKDIR SMBGET
+EOF
+ exit 1
+fi
+
+SERVER=${1}
+SERVER_IP=${2}
+DOMAIN=${3}
+REALM=${4}
+USERNAME=${5}
+PASSWORD=${6}
+DOMAIN_USER=${7}
+DOMAIN_USER_PASSWORD=${8}
+WORKDIR=${9}
+SMBGET="$VALGRIND ${10}"
+shift 10
+
+TMPDIR="$SELFTEST_TMPDIR"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+. "${incdir}/common_test_fns.inc"
+
+samba_kinit=$(system_or_builddir_binary kinit "${BINDIR}" samba4kinit)
+samba_texpect="${BINDIR}/texpect"
+
+create_test_data()
+{
+ pushd $WORKDIR
+ dd if=/dev/urandom bs=1024 count=128 of=testfile
+ chmod 644 testfile
+ mkdir dir1
+ dd if=/dev/urandom bs=1024 count=128 of=dir1/testfile1
+ mkdir dir2
+ dd if=/dev/urandom bs=1024 count=128 of=dir2/testfile2
+ popd
+}
+
+remove_test_data()
+{
+ pushd $WORKDIR
+ rm -rf dir1 dir2 testfile
+ popd
+}
+
+clear_download_area()
+{
+ rm -rf dir1 dir2 testfile dir001 dir004 readable_file
+}
+
+test_singlefile_guest()
+{
+ clear_download_area
+ echo "$SMBGET --verbose --guest smb://$SERVER_IP/smbget_guest/testfile"
+ $SMBGET --verbose --guest smb://$SERVER_IP/smbget_guest/testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+ cmp --silent $WORKDIR/testfile ./testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: file content does not match'
+ return 1
+ fi
+ return 0
+}
+
+test_singlefile_U()
+{
+ clear_download_area
+ $SMBGET --verbose -U${SERVER}/${USERNAME}%$PASSWORD smb://$SERVER_IP/smbget/testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+ cmp --silent $WORKDIR/testfile ./testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: file content does not match'
+ return 1
+ fi
+ return 0
+}
+
+test_singlefile_U_UPN()
+{
+ clear_download_area
+
+ ${SMBGET} --verbose -U"${DOMAIN_USER}@${REALM}%${DOMAIN_USER_PASSWORD}" \
+ "smb://${SERVER_IP}/smbget/testfile"
+ ret=${?}
+ if [ ${ret} -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+
+ cmp --silent "${WORKDIR}/testfile" ./testfile
+ ret=${?}
+ if [ ${ret} -ne 0 ]; then
+ echo 'ERROR: file content does not match'
+ return 1
+ fi
+
+ return 0
+}
+
+test_singlefile_U_domain()
+{
+ clear_download_area
+
+ ${SMBGET} --verbose -U"${DOMAIN}/${DOMAIN_USER}%${DOMAIN_USER_PASSWORD}" \
+ "smb://${SERVER_IP}/smbget/testfile"
+ ret=${?}
+ if [ ${ret} -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+
+ cmp --silent "${WORKDIR}/testfile" ./testfile
+ ret=${?}
+ if [ ${ret} -ne 0 ]; then
+ echo 'ERROR: file content does not match'
+ return 1
+ fi
+
+ return 0
+}
+
+test_singlefile_smburl()
+{
+ clear_download_area
+ $SMBGET --workgroup $DOMAIN smb://${DOMAIN_USER}:$DOMAIN_USER_PASSWORD@$SERVER_IP/smbget/testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+ cmp --silent $WORKDIR/testfile ./testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: file content does not match'
+ return 1
+ fi
+ return 0
+}
+
+test_singlefile_smburl2()
+{
+ clear_download_area
+ $SMBGET "smb://$DOMAIN;${DOMAIN_USER}:$DOMAIN_USER_PASSWORD@$SERVER_IP/smbget/testfile"
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+ cmp --silent $WORKDIR/testfile ./testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: file content does not match'
+ return 1
+ fi
+ return 0
+}
+
+test_singlefile_smburl_interactive()
+{
+ clear_download_area
+
+ tmpfile="$(mktemp --tmpdir="${TMPDIR}" expect_XXXXXXXXXX)"
+
+ cat >"${tmpfile}" <<EOF
+expect Password for
+send ${DOMAIN_USER_PASSWORD}\n
+EOF
+
+ USER="hanswurst" ${samba_texpect} "${tmpfile}" ${SMBGET} "smb://${DOMAIN};${DOMAIN_USER}@${SERVER_IP}/smbget/testfile"
+ ret=$?
+ rm -f "${tmpfile}"
+ if [ ${ret} -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+ cmp --silent $WORKDIR/testfile ./testfile
+ ret=$?
+ if [ ${ret} -ne 0 ]; then
+ echo 'ERROR: file content does not match'
+ return 1
+ fi
+ return 0
+}
+
+test_singlefile_authfile()
+{
+ clear_download_area
+ cat >"${TMPDIR}/authfile" << EOF
+username = ${SERVER}/${USERNAME}
+password = $PASSWORD
+EOF
+ $SMBGET --verbose --authentication-file="${TMPDIR}/authfile" smb://$SERVER_IP/smbget/testfile
+ rc=$?
+ rm -f $TMPDIR/authfile
+ if [ $rc -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+ cmp --silent $WORKDIR/testfile ./testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: file content does not match'
+ return 1
+ fi
+ return 0
+}
+
+test_recursive_U()
+{
+ clear_download_area
+ $SMBGET --verbose --recursive -U${SERVER}/${USERNAME}%$PASSWORD smb://$SERVER_IP/smbget/
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+
+ cmp --silent $WORKDIR/testfile ./testfile &&
+ cmp --silent $WORKDIR/dir1/testfile1 ./dir1/testfile1 &&
+ cmp --silent $WORKDIR/dir2/testfile2 ./dir2/testfile2
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: file content does not match'
+ return 1
+ fi
+
+ return 0
+}
+
+test_recursive_existing_dir()
+{
+ clear_download_area
+ mkdir dir1
+ $SMBGET --verbose --recursive -U${SERVER}/${USERNAME}%$PASSWORD smb://$SERVER_IP/smbget/
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+
+ cmp --silent $WORKDIR/testfile ./testfile &&
+ cmp --silent $WORKDIR/dir1/testfile1 ./dir1/testfile1 &&
+ cmp --silent $WORKDIR/dir2/testfile2 ./dir2/testfile2
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: file content does not match'
+ return 1
+ fi
+
+ return 0
+}
+
+test_recursive_with_empty()
+{ # see Bug 13199
+ clear_download_area
+ # create some additional empty directories
+ mkdir -p $WORKDIR/dir001/dir002/dir003
+ mkdir -p $WORKDIR/dir004/dir005/dir006
+ $SMBGET --verbose --recursive -U${SERVER}/${USERNAME}%$PASSWORD smb://$SERVER_IP/smbget/
+ rc=$?
+ rm -rf $WORKDIR/dir001
+ rm -rf $WORKDIR/dir004
+ if [ $rc -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+
+ cmp --silent $WORKDIR/testfile ./testfile &&
+ cmp --silent $WORKDIR/dir1/testfile1 ./dir1/testfile1 &&
+ cmp --silent $WORKDIR/dir2/testfile2 ./dir2/testfile2
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: file content does not match'
+ return 1
+ fi
+
+ if [ ! -d dir001/dir002/dir003 ] || [ ! -d dir004/dir005/dir006 ]; then
+ echo 'ERROR: empty directories are not present'
+ return 1
+ fi
+
+ return 0
+}
+
+test_resume()
+{
+ clear_download_area
+ cp $WORKDIR/testfile .
+ truncate -s 1024 testfile
+ $SMBGET --verbose --resume -U${SERVER}/${USERNAME}%$PASSWORD smb://$SERVER_IP/smbget/testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+
+ cmp --silent $WORKDIR/testfile ./testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: file content does not match'
+ return 1
+ fi
+
+ return 0
+}
+
+test_resume_modified()
+{
+ clear_download_area
+ dd if=/dev/urandom bs=1024 count=2 of=testfile
+ $SMBGET --verbose --resume -U${SERVER}/${USERNAME}%$PASSWORD smb://$SERVER_IP/smbget/testfile
+ if [ $? -ne 1 ]; then
+ echo 'ERROR: RC does not match, expected: 1'
+ return 1
+ fi
+
+ return 0
+}
+
+test_update()
+{
+ clear_download_area
+ $SMBGET --verbose -U${SERVER}/${USERNAME}%$PASSWORD smb://$SERVER_IP/smbget/testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+
+ # secondary download should pass
+ $SMBGET --verbose --update -U${SERVER}/${USERNAME}%$PASSWORD smb://$SERVER_IP/smbget/testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+
+ echo "modified" >>testfile
+ # touch source to trigger new download
+ sleep 1
+ touch -m $WORKDIR/testfile
+ $SMBGET --verbose --update -U${SERVER}/${USERNAME}%$PASSWORD smb://$SERVER_IP/smbget/testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+
+ cmp --silent $WORKDIR/testfile ./testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: file content does not match'
+ return 1
+ fi
+
+ return 0
+}
+
+# Test accessing an msdfs path.
+test_msdfs_link()
+{
+ clear_download_area
+
+ ${SMBGET} --verbose "-U${SERVER}/${USERNAME}%${PASSWORD}" \
+ "smb://${SERVER}/msdfs-share/deeppath/msdfs-src2/readable_file"
+ ret=$?
+ if [ ${ret} -ne 0 ]; then
+ echo "ERROR: smbget failed with ${ret}"
+ return 1
+ fi
+
+ return 0
+}
+
+test_msdfs_link_domain()
+{
+ clear_download_area
+
+ ${SMBGET} --verbose "-U${DOMAIN}/${DOMAIN_USER}%${DOMAIN_USER_PASSWORD}" \
+ "smb://${SERVER}/msdfs-share/deeppath/msdfs-src2/readable_file"
+ ret=$?
+ if [ ${ret} -ne 0 ]; then
+ echo "ERROR: smbget failed with ${ret}"
+ return 1
+ fi
+
+ return 0
+}
+
+test_msdfs_link_upn()
+{
+ clear_download_area
+
+ ${SMBGET} --verbose "-U${DOMAIN_USER}@${REALM}%${DOMAIN_USER_PASSWORD}" \
+ "smb://${SERVER}/msdfs-share/deeppath/msdfs-src2/readable_file"
+ ret=$?
+ if [ ${ret} -ne 0 ]; then
+ echo "ERROR: smbget failed with ${ret}"
+ return 1
+ fi
+
+ return 0
+}
+
+# Tests --limit-rate. Getting the testfile (128K in size) with --limit-rate 100
+# (that is 100KB/s) should take at least 1 sec to complete.
+test_limit_rate()
+{
+ clear_download_area
+ echo "$SMBGET --verbose --guest --limit-rate 100 smb://$SERVER_IP/smbget_guest/testfile"
+ time_begin=$(date +%s)
+ $SMBGET --verbose --guest --limit-rate 100 smb://$SERVER_IP/smbget_guest/testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+ time_end=$(date +%s)
+ cmp --silent $WORKDIR/testfile ./testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: file content does not match'
+ return 1
+ fi
+ if [ $((time_end - time_begin)) -lt 1 ]; then
+ echo 'ERROR: It should take at least 1s to transfer 128KB with rate 100KB/s'
+ return 1
+ fi
+ return 0
+}
+
+test_encrypt()
+{
+ clear_download_area
+ $SMBGET --verbose --encrypt -U${SERVER}/${USERNAME}%$PASSWORD smb://$SERVER_IP/smbget/testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+ cmp --silent $WORKDIR/testfile ./testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: file content does not match'
+ return 1
+ fi
+
+ clear_download_area
+ $SMBGET --verbose --client-protection=encrypt -U${SERVER}/${USERNAME}%$PASSWORD smb://$SERVER_IP/smbget/testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+ cmp --silent $WORKDIR/testfile ./testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: file content does not match'
+ return 1
+ fi
+
+ return 0
+}
+
+test_kerberos()
+{
+ clear_download_area
+
+ KRB5CCNAME_PATH="${TMPDIR}/smget_krb5ccache"
+ rm -f "${KRB5CCNAME_PATH}"
+
+ KRB5CCNAME="FILE:${KRB5CCNAME_PATH}"
+ export KRB5CCNAME
+ kerberos_kinit "${samba_kinit}" \
+ "${DOMAIN_USER}@${REALM}" "${DOMAIN_USER_PASSWORD}"
+ if [ $? -ne 0 ]; then
+ echo 'Failed to get Kerberos ticket'
+ return 1
+ fi
+
+ $SMBGET --verbose --use-krb5-ccache="${KRB5CCNAME}" \
+ smb://$SERVER/smbget/testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+
+ cmp --silent $WORKDIR/testfile ./testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: file content does not match'
+ return 1
+ fi
+
+ rm -f "${KRB5CCNAME_PATH}"
+
+ return 0
+}
+
+test_kerberos_trust()
+{
+ clear_download_area
+
+ $SMBGET --verbose --use-kerberos=required \
+ -U"${TRUST_F_BOTH_USERNAME}@${TRUST_F_BOTH_REALM}%${TRUST_F_BOTH_PASSWORD}" \
+ smb://$SERVER.${REALM}/smbget/testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: RC does not match, expected: 0'
+ return 1
+ fi
+
+ cmp --silent $WORKDIR/testfile ./testfile
+ if [ $? -ne 0 ]; then
+ echo 'ERROR: file content does not match'
+ return 1
+ fi
+
+ return 0
+}
+
+# TODO FIXME
+# This test does not work, as we can't tell the libsmb code that the
+# principal is an enterprice principal. We need support for enterprise
+# principals in kerberos_kinit_password_ext() and a way to pass it via the
+# credenitals structure and commandline options.
+# It works if you do: kinit -E testdenied_upn@${REALM}.upn
+#
+# test_kerberos_upn_denied()
+# {
+# set -x
+# clear_download_area
+#
+# $SMBGET --verbose --use-kerberos=required \
+# -U"testdenied_upn@${REALM}.upn%${DC_PASSWORD}" \
+# "smb://${SERVER}.${REALM}/smbget/testfile" -d10
+# if [ $? -ne 0 ]; then
+# echo 'ERROR: RC does not match, expected: 0'
+# return 1
+# fi
+#
+# cmp --silent $WORKDIR/testfile ./testfile
+# if [ $? -ne 0 ]; then
+# echo 'ERROR: file content does not match'
+# return 1
+# fi
+#
+# return 0
+# }
+
+create_test_data
+
+pushd $TMPDIR
+
+failed=0
+testit "download single file as guest" test_singlefile_guest ||
+ failed=$(expr $failed + 1)
+
+testit "download single file with -U" test_singlefile_U ||
+ failed=$(expr $failed + 1)
+
+testit "download single file with --update and domain" test_singlefile_U_domain ||
+ failed=$((failed + 1))
+
+testit "download single file with --update and UPN" test_singlefile_U_UPN ||
+ failed=$((failed + 1))
+
+testit "download single file with smb URL" test_singlefile_smburl ||
+ failed=$(expr $failed + 1)
+
+testit "download single file with smb URL including domain" \
+ test_singlefile_smburl2 ||
+ failed=$(expr $failed + 1)
+
+testit "download single file with smb URL interactive" \
+ test_singlefile_smburl_interactive ||
+ failed=$(expr $failed + 1)
+
+testit "download single file with authfile" test_singlefile_authfile ||
+ failed=$(expr $failed + 1)
+
+testit "recursive download" test_recursive_U ||
+ failed=$(expr $failed + 1)
+
+testit "recursive download (existing target dir)" test_recursive_existing_dir ||
+ failed=$(expr $failed + 1)
+
+testit "recursive download with empty directories" test_recursive_with_empty ||
+ failed=$(expr $failed + 1)
+
+testit "resume download" test_resume ||
+ failed=$(expr $failed + 1)
+
+testit "resume download (modified file)" test_resume_modified ||
+ failed=$(expr $failed + 1)
+
+testit "update" test_update ||
+ failed=$(expr $failed + 1)
+
+testit "msdfs" test_msdfs_link ||
+ failed=$((failed + 1))
+
+testit "msdfs.domain" test_msdfs_link_domain ||
+ failed=$((failed + 1))
+
+testit "msdfs.upn" test_msdfs_link_upn ||
+ failed=$((failed + 1))
+
+testit "limit rate" test_limit_rate ||
+ failed=$((failed + 1))
+
+testit "encrypt" test_encrypt ||
+ failed=$((failed + 1))
+
+testit "kerberos" test_kerberos ||
+ failed=$((failed + 1))
+
+testit "kerberos_trust" test_kerberos_trust ||
+ failed=$((failed + 1))
+
+# testit "kerberos_upn_denied" test_kerberos_upn_denied ||
+# failed=$((failed + 1))
+
+clear_download_area
+
+popd # TMPDIR
+
+remove_test_data
+
+exit $failed
diff --git a/source3/script/tests/test_smbpasswd.sh b/source3/script/tests/test_smbpasswd.sh
new file mode 100755
index 0000000..b4d4f40
--- /dev/null
+++ b/source3/script/tests/test_smbpasswd.sh
@@ -0,0 +1,133 @@
+#!/bin/sh
+#
+# Blackbox tests for smbpasswd
+#
+# Copyright (c) 2015-2016 Andreas Schneider <asn@samba.org>
+#
+
+if [ $# -lt 4 ]; then
+ cat <<EOF
+Usage: test_smbpasswd.sh SERVER USERNAME PASSWORD
+EOF
+ exit 1
+fi
+
+SERVER=$1
+SERVER_IP=$2
+USERNAME=$3
+PASSWORD=$4
+shift 4
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+samba_bindir="$BINDIR"
+samba_srcdir="$SRCDIR"
+
+samba_texpect="$samba_bindir/texpect"
+samba_smbpasswd="$samba_bindir/smbpasswd"
+
+samba_test_user="alice_smbpasswd"
+samba_test_user_pwd="Secret007"
+samba_test_user_new_pwd="Secret008"
+
+create_local_smb_user()
+{
+ user=$1
+ password=$2
+
+ tmpfile=$PREFIX/smbpasswd_create_user_script
+ cat >$tmpfile <<EOF
+expect New SMB password:
+send $password\n
+expect Retype new SMB password:
+send $password\n
+EOF
+
+ cmd='UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 $samba_texpect $tmpfile $samba_smbpasswd -c $SMB_CONF_PATH -a $user 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+
+ rm -f $tmpfile
+
+ if [ $ret -ne 0 ]; then
+ echo "Failed to create smb user $user"
+ return 1
+ fi
+
+ getent passwd $user
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "Failed to create smb user $user"
+ return 1
+ fi
+}
+
+delete_local_smb_user()
+{
+ user=$1
+
+ # This also deletes the unix account!
+ UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 $samba_smbpasswd -c $SMB_CONF_PATH -x $user
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "Failed to delete smb user $user"
+ return 1
+ fi
+}
+
+test_smbpasswd()
+{
+ user=$1
+ oldpwd=$2
+ newpwd=$3
+
+ user_id=$(id -u $user)
+
+ tmpfile=$PREFIX/smbpasswd_change_password_script
+ cat >$tmpfile <<EOF
+expect Old SMB password:
+send $oldpwd\n
+expect New SMB password:
+send $newpwd\n
+expect Retype new SMB password:
+send $newpwd\n
+EOF
+
+ cmd='UID_WRAPPER_INITIAL_RUID=$user_id UID_WRAPPER_INITIAL_EUID=$user_id $samba_texpect $tmpfile $samba_smbpasswd -c $SMB_CONF_PATH -r $SERVER 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+ if [ $ret -ne 0 ]; then
+ echo "Failed to change user password $user"
+ echo "${out}"
+ return 1
+ fi
+
+ prompt="Password changed for user $user"
+ echo "$out" | grep "$prompt" >/dev/null 2>&1
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "Failed to change password for user $user"
+ echo "$out"
+ return 1
+ fi
+}
+
+testit "Create user $samba_test_user" \
+ create_local_smb_user $samba_test_user $samba_test_user_pwd ||
+ failed=$(expr $failed + 1)
+
+testit "Change user password" \
+ test_smbpasswd $samba_test_user $samba_test_user_pwd $samba_test_user_new_pwd ||
+ failed=$(expr $failed + 1)
+
+testit "Delete user $samba_test_user" \
+ delete_local_smb_user $samba_test_user ||
+ failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source3/script/tests/test_smbspool.sh b/source3/script/tests/test_smbspool.sh
new file mode 100755
index 0000000..2036d57
--- /dev/null
+++ b/source3/script/tests/test_smbspool.sh
@@ -0,0 +1,294 @@
+#!/bin/sh
+
+if [ $# -lt 4 ]; then
+ cat <<EOF
+Usage: test_smbspool.sh SERVER SERVER_IP USERNAME PASSWORD TARGET_ENV
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+SERVER_IP="$2"
+USERNAME="$3"
+PASSWORD="$4"
+TARGET_ENV="$5"
+shift 5
+ADDARGS="$@"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+. $incdir/common_test_fns.inc
+
+samba_bindir="$BINDIR"
+samba_vlp="$samba_bindir/vlp"
+samba_smbspool="$samba_bindir/smbspool"
+samba_argv_wrapper="$samba_bindir/smbspool_argv_wrapper"
+samba_smbtorture3="$samba_bindir/smbtorture3"
+samba_smbspool_krb5="$samba_bindir/smbspool_krb5_wrapper"
+
+test_smbspool_noargs()
+{
+ cmd='$1 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed to execute $1"
+ fi
+
+ echo "$out" | grep 'network smb "Unknown" "Windows Printer via SAMBA"'
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "$out"
+ return 1
+ fi
+}
+
+test_smbspool_authinforequired_none()
+{
+ cmd='$samba_smbspool_krb5 smb://$SERVER_IP/print4 200 $USERNAME "Testprint" 1 "options" $SRCDIR/testdata/printing/example.ps 2>&1'
+
+ AUTH_INFO_REQUIRED="none"
+ export AUTH_INFO_REQUIRED
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ unset AUTH_INFO_REQUIRED
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed to execute $samba_smbspool_krb5"
+ return 1
+ fi
+
+ return 0
+}
+
+test_smbspool_authinforequired_unknown()
+{
+ cmd='$samba_smbspool_krb5 smb://$SERVER_IP/print4 200 $USERNAME "Testprint" 1 "options" $SRCDIR/testdata/printing/example.ps 2>&1'
+
+ # smbspool_krb5_wrapper must ignore AUTH_INFO_REQUIRED unknown to him and pass the task to smbspool
+ # smbspool must fail with NT_STATUS_ACCESS_DENIED (22)
+ # "jjf4wgmsbc0" is just a random string
+ AUTH_INFO_REQUIRED="jjf4wgmsbc0"
+ export AUTH_INFO_REQUIRED
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ unset AUTH_INFO_REQUIRED
+
+ case "$ret" in
+ 2) return 0 ;;
+ *)
+ echo "ret=$ret"
+ echo "$out"
+ echo "failed to test $samba_smbspool_krb5 against unknown value of AUTH_INFO_REQUIRED"
+ return 1
+ ;;
+ esac
+}
+
+#
+# The test environment uses 'vlp' (virtual lp) as the printing backend.
+#
+# When using the vlp backend the print job is only written to the database.
+# The job needs to removed manually using 'vlp lprm' command!
+#
+# This calls the 'vlp' command to check if the print job has been successfully
+# added to the database and also makes sure the temporary print file has been
+# created.
+#
+# The function removes the print job from the vlp database if successful.
+#
+test_vlp_verify()
+{
+ tdbfile="$PREFIX_ABS/$TARGET_ENV/lockdir/vlp.tdb"
+ if [ ! -w $tdbfile ]; then
+ echo "vlp tdbfile $tdbfile doesn't exist or is not writeable!"
+ return 1
+ fi
+
+ cmd='$samba_vlp tdbfile=$tdbfile lpq print1 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "failed to get print queue with $samba_vlp"
+ echo "$out"
+ fi
+
+ jobid=$(echo "$out" | awk '/[0-9]+/ { print $1 };')
+ if [ -z "$jobid" ] || [ $jobid -lt 100 ] || [ $jobid -gt 2000 ]; then
+ echo "Invalid jobid: $jobid"
+ echo "$out"
+ return 1
+ fi
+
+ file=$(echo "$out" | awk '/[0-9]+/ { print $6 };')
+ if [ ! -r $PREFIX_ABS/$TARGET_ENV/share/$file ]; then
+ echo "$file doesn't exist"
+ echo "$out"
+ return 1
+ fi
+
+ $samba_vlp "tdbfile=$tdbfile" lprm print1 $jobid
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "Failed to remove jobid $jobid from $tdbfile"
+ return 1
+ fi
+}
+
+test_delete_on_close()
+{
+ tdbfile="$PREFIX_ABS/$TARGET_ENV/lockdir/vlp.tdb"
+ if [ ! -w $tdbfile ]; then
+ echo "vlp tdbfile $tdbfile doesn't exist or is not writeable!"
+ return 1
+ fi
+
+ cmd='$samba_vlp tdbfile=$tdbfile lpq print1 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "failed to lpq jobs on print1 with $samba_vlp"
+ echo "$out"
+ return 1
+ fi
+
+ num_jobs=$(echo "$out" | wc -l)
+ #
+ # Now run the test DELETE-PRINT from smbtorture3
+ #
+ cmd='$samba_smbtorture3 //$SERVER_IP/print1 -U$USERNAME%$PASSWORD DELETE-PRINT 2>&1'
+ eval echo "$cmd"
+ out_t=$(eval $cmd)
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "failed to run DELETE-PRINT on print1"
+ echo "$out_t"
+ return 1
+ fi
+
+ cmd='$samba_vlp tdbfile=$tdbfile lpq print1 2>&1'
+ eval echo "$cmd"
+ out1=$(eval $cmd)
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "(2) failed to lpq jobs on print1 with $samba_vlp"
+ echo "$out1"
+ return 1
+ fi
+ num_jobs1=$(echo "$out1" | wc -l)
+
+ #
+ # Number of jobs should not change. Job
+ # should not have made it to backend.
+ #
+ if [ "$num_jobs1" -ne "$num_jobs" ]; then
+ echo "delete-on-close fail $num_jobs1 -ne $num_jobs"
+ echo "$out"
+ echo "$out_t"
+ echo "$out1"
+ return 1
+ fi
+
+ return 0
+}
+
+testit "smbspool no args" \
+ test_smbspool_noargs $samba_smbspool ||
+ failed=$(expr $failed + 1)
+
+testit "smbspool_krb5_wrapper no args" \
+ test_smbspool_noargs $samba_smbspool_krb5 ||
+ failed=$(expr $failed + 1)
+
+testit "smbspool_krb5_wrapper AuthInfoRequired=none" \
+ test_smbspool_authinforequired_none ||
+ failed=$(expr $failed + 1)
+
+testit "smbspool_krb5_wrapper AuthInfoRequired=(sth unknown)" \
+ test_smbspool_authinforequired_unknown ||
+ failed=$(expr $failed + 1)
+
+testit "smbspool print example.ps" \
+ $samba_smbspool smb://$USERNAME:$PASSWORD@$SERVER_IP/print1 200 $USERNAME "Testprint" 1 "options" $SRCDIR/testdata/printing/example.ps ||
+ failed=$(expr $failed + 1)
+
+testit "vlp verify example.ps" \
+ test_vlp_verify ||
+ failed=$(expr $failed + 1)
+
+testit "smbspool print example.ps via stdin" \
+ $samba_smbspool smb://$USERNAME:$PASSWORD@$SERVER_IP/print1 200 $USERNAME "Testprint" 1 "options" <$SRCDIR/testdata/printing/example.ps ||
+ failed=$(expr $failed + 1)
+
+testit "vlp verify example.ps" \
+ test_vlp_verify ||
+ failed=$(expr $failed + 1)
+
+DEVICE_URI="smb://$USERNAME:$PASSWORD@$SERVER_IP/print1"
+export DEVICE_URI
+testit "smbspool print DEVICE_URI example.ps" \
+ $samba_smbspool 200 $USERNAME "Testprint" 1 "options" $SRCDIR/testdata/printing/example.ps ||
+ failed=$(expr $failed + 1)
+unset DEVICE_URI
+
+testit "vlp verify example.ps" \
+ test_vlp_verify ||
+ failed=$(expr $failed + 1)
+
+DEVICE_URI="smb://$USERNAME:$PASSWORD@$SERVER_IP/print1"
+export DEVICE_URI
+testit "smbspool print DEVICE_URI example.ps via stdin" \
+ $samba_smbspool 200 $USERNAME "Testprint" 1 "options" <$SRCDIR/testdata/printing/example.ps ||
+ failed=$(expr $failed + 1)
+unset DEVICE_URI
+
+testit "vlp verify example.ps" \
+ test_vlp_verify ||
+ failed=$(expr $failed + 1)
+
+DEVICE_URI="smb://$USERNAME:$PASSWORD@$SERVER_IP/print1"
+export DEVICE_URI
+testit "smbspool print sanitized Device URI in argv0 example.ps" \
+ $samba_argv_wrapper $samba_smbspool smb://$SERVER_IP/print1 200 $USERNAME "Testprint" 1 "options" $SRCDIR/testdata/printing/example.ps ||
+ failed=$(expr $failed + 1)
+unset DEVICE_URI
+
+testit "vlp verify example.ps" \
+ test_vlp_verify ||
+ failed=$(expr $failed + 1)
+
+DEVICE_URI="smb://$USERNAME:$PASSWORD@$SERVER_IP/print1"
+export DEVICE_URI
+testit "smbspool print sanitized Device URI in argv0 example.ps via stdin" \
+ $samba_argv_wrapper $samba_smbspool smb://$SERVER_IP/print1 200 $USERNAME "Testprint" 1 "options" <$SRCDIR/testdata/printing/example.ps ||
+ failed=$(expr $failed + 1)
+unset DEVICE_URI
+
+testit "vlp verify example.ps" \
+ test_vlp_verify ||
+ failed=$(expr $failed + 1)
+
+AUTH_INFO_REQUIRED="username,password"
+export AUTH_INFO_REQUIRED
+testit "smbspool_krb5(username,password) print example.ps" \
+ $samba_smbspool_krb5 smb://$USERNAME:$PASSWORD@$SERVER_IP/print1 200 $USERNAME "Testprint" 1 "options" $SRCDIR/testdata/printing/example.ps ||
+ failed=$(expr $failed + 1)
+
+testit "vlp verify example.ps" \
+ test_vlp_verify ||
+ failed=$(expr $failed + 1)
+unset AUTH_INFO_REQUIRED
+
+testit "delete on close" \
+ test_delete_on_close ||
+ failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source3/script/tests/test_smbspool_krb.sh b/source3/script/tests/test_smbspool_krb.sh
new file mode 100755
index 0000000..a4aeeab
--- /dev/null
+++ b/source3/script/tests/test_smbspool_krb.sh
@@ -0,0 +1,90 @@
+#!/bin/sh
+
+if [ $# -lt 3 ]; then
+ cat <<EOF
+Usage: test_smbspool_krb.sh SERVER USERNAME PASSWORD REALM
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+USERNAME="$2"
+PASSWORD="$3"
+REALM="$4"
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. $incdir/subunit.sh
+. $incdir/common_test_fns.inc
+
+samba_bindir="$BINDIR"
+samba_smbspool="$samba_bindir/smbspool"
+
+samba_kinit=kinit
+if test -x "${BINDIR}/samba4kinit"; then
+ samba_kinit=${BINDIR}/samba4kinit
+fi
+
+samba_kdestroy=kdestroy
+if test -x "${BINDIR}/samba4kdestroy"; then
+ samba_kdestroy=${BINDIR}/samba4kdestroy
+fi
+
+KRB5CCNAME_PATH="${PREFIX}/ccache_smbclient_kerberos"
+KRB5CCNAME="FILE:${KRB5CCNAME_PATH}"
+export KRB5CCNAME
+
+test_smbspool_authinforequired_negotiate()
+{
+ cmd='$samba_smbspool smb://$SERVER/print3 200 $USERNAME "Testprint" 1 "options" $SRCDIR/testdata/printing/example.ps 2>&1'
+
+ AUTH_INFO_REQUIRED="negotiate"
+ export AUTH_INFO_REQUIRED
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+ unset AUTH_INFO_REQUIRED
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed to execute $samba_smbspool"
+ return 1
+ fi
+
+ return 0
+}
+
+test_smbspool_authinforequired_negative()
+{
+ cmd='$samba_smbspool smb://$SERVER/print3 200 $USERNAME "Testprint" 1 "options" $SRCDIR/testdata/printing/example.ps 2>&1'
+
+ AUTH_INFO_REQUIRED="negotiate"
+ export AUTH_INFO_REQUIRED
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+ unset AUTH_INFO_REQUIRED
+
+ if [ $ret = 0 ]; then
+ echo "$out"
+ echo "Unexpected success to execute $samba_smbspool"
+ return 1
+ fi
+
+ return 0
+}
+
+kerberos_kinit "$samba_kinit" "${USERNAME}@${REALM}" "${PASSWORD}"
+testit "smbspool krb5 AuthInfoRequired=negotiate" \
+ test_smbspool_authinforequired_negotiate ||
+ failed=$((failed + 1))
+
+$samba_kdestroy
+rm -rf "$KRB5CCNAME_PATH"
+
+# smbspool should fail after destroying kerberos credentials
+testit "smbspool krb5 AuthInfoRequired=negotiate negative test" \
+ test_smbspool_authinforequired_negative ||
+ failed=$((failed + 1))
+
+
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_smbstatus.sh b/source3/script/tests/test_smbstatus.sh
new file mode 100755
index 0000000..30ca239
--- /dev/null
+++ b/source3/script/tests/test_smbstatus.sh
@@ -0,0 +1,479 @@
+#!/bin/sh
+
+# This runs smbstatus tests
+
+if [ $# -lt 12 ]; then
+ echo "Usage: test_smbstatus.sh SERVER SERVER_IP DOMAIN USERNAME PASSWORD USERID LOCAL_PATH PREFIX SMBCLIENT CONFIGURATION PROTOCOL"
+ exit 1
+fi
+
+SERVER="${1}"
+SERVER_IP="${2}"
+DOMAIN="${3}"
+USERNAME="${4}"
+PASSWORD="${5}"
+USERID="${6}"
+LOCAL_PATH="${7}"
+PREFIX="${8}"
+SMBCLIENT="${9}"
+SMBSTATUS="${10}"
+CONFIGURATION="${11}"
+PROTOCOL="${12}"
+
+shift 12
+
+RAWARGS="${CONFIGURATION} -m${PROTOCOL}"
+ADDARGS="${RAWARGS} $@"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+test_smbstatus()
+{
+ local cmdfile=$PREFIX/smbclient_commands
+ local tmpfile=$PREFIX/smclient_lock_file
+ local file=smclient_lock_file
+ local cmd=""
+ local ret=0
+ local userid=$(id -u $USERNAME)
+
+ cat >$tmpfile <<EOF
+What a Wurst!
+EOF
+ cat >$cmdfile <<EOF
+lcd $PREFIX_ABS
+put $file
+open $file
+!UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 $SMBSTATUS
+close 1
+rm $file
+quit
+EOF
+
+ cmd="CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS --quiet < $cmdfile 2>&1"
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $cmpfile
+ rm -f $tmpfile
+
+ if [ $ret -ne 0 ]; then
+ echo "Failed to run smbclient with error $ret"
+ echo "$out"
+ false
+ return
+ fi
+
+ echo "$out" | grep -c 'NT_STATUS_'
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "Failed: got an NT_STATUS error!"
+ echo "$out"
+ false
+ return
+ fi
+
+ echo "$out" | grep "${userid}[ ]*DENY_NONE"
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "Failed to find userid in smbstatus locked file output"
+ echo "$out"
+ false
+ return
+ fi
+
+ return 0
+}
+
+test_smbstatus_resolve_uids()
+{
+ local cmdfile=$PREFIX/smbclient_commands
+ local tmpfile=$PREFIX/smclient_lock_file
+ local file=smclient_lock_file
+ local cmd=""
+ local ret=0
+ local userid=$(id -u $USERNAME)
+
+ cat >$tmpfile <<EOF
+What a Wurst!
+EOF
+ cat >$cmdfile <<EOF
+lcd $PREFIX_ABS
+put $file
+open $file
+!UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 $SMBSTATUS --resolve-uids
+close 1
+rm $file
+quit
+EOF
+
+ cmd="CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS --quiet < $cmdfile 2>&1"
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $cmpfile
+ rm -f $tmpfile
+
+ if [ $ret -ne 0 ]; then
+ echo "Failed to run smbclient with error $ret"
+ echo "$out"
+ false
+ return
+ fi
+
+ echo "$out" | grep -c 'NT_STATUS_'
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "Failed: got an NT_STATUS error!"
+ echo "$out"
+ false
+ return
+ fi
+
+ echo "$out" | grep "${USERNAME}[ ]*DENY_NONE"
+ ret=$?
+ if [ $ret != 0 ]; then
+ echo "Failed to find userid in smbstatus locked file output"
+ echo "$out"
+ false
+ return
+ fi
+
+ return 0
+}
+
+test_smbstatus_output()
+{
+ local cmdfile=$PREFIX/smbclient_commands
+ local tmpfile=$PREFIX/smbclient_lock_file
+ local file=smbclient_lock_file
+ local status_shares=smbstatus_output_shares
+ local status_processes=smbstatus_output_processes
+ local status_locks=smbstatus_output_locks
+
+ cat >$tmpfile <<EOF
+Hello World!
+EOF
+ cat >$cmdfile <<EOF
+lcd $PREFIX_ABS
+put $file
+open $file
+!UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 $SMBSTATUS --shares > $status_shares
+!UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 $SMBSTATUS --processes > $status_processes
+!UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 $SMBSTATUS --locks > $status_locks
+close 1
+rm $file
+quit
+EOF
+
+ cmd="CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS --quiet < $cmdfile 2>&1"
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+
+ rm -f $cmpfile
+ rm -f $tmpfile
+
+ if [ $ret -ne 0 ]; then
+ echo "Failed to run smbclient with error $ret"
+ echo "$out"
+ return 1
+ fi
+
+ out=$(cat $PREFIX/$status_processes)
+ echo "$out" | grep -c 'PID *Username'
+ ret=$?
+ if [ $ret -eq 1 ]; then
+ echo "Failed: Could not start smbstatus"
+ echo "$out"
+ return 1
+ fi
+ echo "$out" | grep -c "$USERNAME"
+ ret=$?
+ if [ $ret -eq 1 ]; then
+ echo "Failed: open connection not found"
+ echo "$out"
+ return 1
+ fi
+
+ out=$(cat $PREFIX/$status_shares)
+ echo "$out" | grep -c 'Service *pid'
+ ret=$?
+ if [ $ret -eq 1 ]; then
+ echo "Failed: Could not start smbstatus"
+ echo "$out"
+ return 1
+ fi
+ echo "$out" | grep -c "tmp"
+ ret=$?
+ if [ $ret -eq 1 ]; then
+ echo "Failed: shares not found"
+ echo "$out"
+ return 1
+ fi
+
+ out=$(cat $PREFIX/$status_locks)
+ echo "$out" | grep -c "Locked files:"
+ ret=$?
+ if [ $ret -eq 1 ]; then
+ echo "Failed: locked file not found"
+ echo "$out"
+ return 1
+ fi
+ echo "$out" | grep -c "$file"
+ ret=$?
+ if [ $ret -eq 1 ]; then
+ echo "Failed: wrong file locked"
+ echo "$out"
+ return 1
+ fi
+
+ rm $PREFIX/$status_shares
+ rm $PREFIX/$status_processes
+ rm $PREFIX/$status_locks
+
+ return 0
+}
+
+test_smbstatus_json()
+{
+ local cmdfile=$PREFIX/smbclient_commands
+ local tmpfile=$PREFIX/smbclient_lock_file
+ local file=smbclient_lock_file
+ local status_json=smbstatus_output_json
+ local status_json_long=smbstatus_output_json_long
+
+ cat > $tmpfile <<EOF
+Hello World!
+EOF
+ cat > $cmdfile <<EOF
+lcd $PREFIX_ABS
+put $file
+open $file
+posix
+!UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 $SMBSTATUS --json > $status_json
+!UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 $SMBSTATUS --json -vBN > $status_json_long
+close 1
+rm $file
+quit
+EOF
+
+ cmd="CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS --quiet < $cmdfile 2>&1"
+ out=$(eval $cmd)
+ echo $out
+ ret=$?
+
+ rm -f $cmdfile
+ rm -f $tmpfile
+
+ if [ $ret -ne 0 ]; then
+ echo "Failed to run smbclient with error $ret"
+ echo "$out"
+ return 1
+ fi
+
+ echo $out | grep -c 'JSON support not available, please install lib Jansson'
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ subunit_start_test "test_smbstatus_json"
+ subunit_skip_test "test_smbstatus_json" <<EOF
+Test needs Jansson
+EOF
+ return 0
+ fi
+
+ out=$(cat $PREFIX/$status_json)
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "Failed: Could not print json output with error $ret"
+ echo "$out"
+ return 1
+ fi
+
+ out=$(cat $PREFIX/$status_json | jq ".")
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "Failed: Could not parse json output from smbstatus with error $ret"
+ echo "$out"
+ return 1
+ fi
+
+ # keys in --json
+ expected='["open_files","sessions","smb_conf","tcons","timestamp","version"]'
+ out=$(cat $PREFIX/$status_json | jq keys -c)
+ if [ "$expected" != "$out" ]; then
+ echo "Failed: Unexpected keys in smbstatus --json"
+ echo "Expected: $expected"
+ echo "Output: $out"
+ return 1
+ fi
+
+ # keys in --json -vBN
+ expected='["byte_range_locks","notifies","open_files","sessions","smb_conf","tcons","timestamp","version"]'
+ out=$(cat $PREFIX/$status_json_long | jq keys -c)
+ if [ "$expected" != "$out" ]; then
+ echo "Failed: Unexpected keys in smbstatus --json"
+ echo "Expected: $expected"
+ echo "Output: $out"
+ return 1
+ fi
+
+ # shares information in --json
+ out=$(cat $PREFIX/$status_json | jq ".tcons|.[].machine")
+ if [ "\"$SERVER_IP\"" != "$out" ]; then
+ echo "Failed: Unexpected value for tcons.machine in smbstatus --json"
+ echo "Expected: $SERVER_IP"
+ echo "Output: $out"
+ return 1
+ fi
+ out=$(cat $PREFIX/$status_json | jq ".tcons|.[].service")
+ if [ '"tmp"' != "$out" ]; then
+ echo "Failed: Unexpected value for tcons.service in smbstatus --json"
+ echo "Expected: tmp"
+ echo "Output: $out"
+ return 1
+ fi
+
+ # session information in --json
+ out=$(cat $PREFIX/$status_json | jq ".sessions|.[].username")
+ if [ "\"$USER\"" != "$out" ]; then
+ echo "Failed: Unexpected value for sessions.username in smbstatus --json"
+ echo "Expected: $USER"
+ echo "Output: $out"
+ return 1
+ fi
+ out=$(cat $PREFIX/$status_json | jq -c ".sessions|.[].signing")
+ expected='{"cipher":"AES-128-GMAC","degree":"partial"}'
+ if [ "$expected" != "$out" ]; then
+ echo "Failed: Unexpected value for sessions.signing in smbstatus --json"
+ echo "Expected: partial(AES-128-GMAC)"
+ echo "Output: $out"
+ return 1
+ fi
+ out=$(cat $PREFIX/$status_json | jq ".sessions|.[].remote_machine")
+ if [ "\"$SERVER_IP\"" != "$out" ]; then
+ echo "Failed: Unexpected value for sessions.remote_machine in smbstatus --json"
+ echo "Expected: $SERVER_IP"
+ echo "Output: $out"
+ return 1
+ fi
+
+ # open_files information in --json
+ out=$(cat $PREFIX/$status_json | jq ".open_files|.[].filename")
+ if [ "\"$file\"" != "$out" ]; then
+ echo "Failed: Unexpected value for open_files.denymode in smbstatus --json"
+ echo "Expected: \"$file\""
+ echo "Output: $out"
+ return 1
+ fi
+ out=$(cat $PREFIX/$status_json | jq ".open_files|.[].opens|.[].access_mask.hex")
+ if [ '"0x00000003"' != "$out" ]; then
+ echo "Failed: Unexpected value for open_files.access_mask.hex in smbstatus --json"
+ echo "Expected: 0x00000003"
+ echo "Output: $out"
+ return 1
+ fi
+
+ rm $PREFIX/$status_json
+ rm $PREFIX/$status_json_long
+
+ return 0
+}
+test_smbstatus_json_profile()
+{
+ local status_json=smbstatus_output_json_profile
+
+ cmd="UID_WRAPPER_INITIAL_RUID=0 UID_WRAPPER_INITIAL_EUID=0 $SMBSTATUS --json --profile > $PREFIX/$status_json"
+ out=$(eval $cmd)
+ ret=$?
+
+ if [ $ret -ne 0 ]; then
+ echo "Failed to run smbstatus -jP with error $ret"
+ echo "$out"
+ return 1
+ fi
+
+ echo $out | grep -c 'JSON support not available, please install lib Jansson'
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ subunit_start_test "test_smbstatus_json_profile"
+ subunit_skip_test "test_smbstatus_json_profile" <<EOF
+Test needs Jansson
+EOF
+ return 0
+ fi
+
+ out=$(cat $PREFIX/$status_json)
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "Failed: Could not print json profile output with error $ret"
+ echo "$out"
+ return 1
+ fi
+
+ out=$(cat $PREFIX/$status_json | jq ".")
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "Failed: Could not parse json output from smbstatus -jP with error $ret"
+ echo "$out"
+ return 1
+ fi
+
+ # keys in --json --profile
+ expected='["ACL Calls","NT Transact Calls","SMB Calls","SMB2 Calls","SMBD loop","Stat Cache","System Calls","Trans2 Calls","smb_conf","timestamp","version"]'
+ out=$(cat $PREFIX/$status_json | jq keys -c)
+ if [ "$expected" != "$out" ]; then
+ echo "Failed: Unexpected keys in smbstatus -jP"
+ echo "Expected: $expected"
+ echo "Output: $out"
+ return 1
+ fi
+
+ # keys in ACL Calls
+ expected='["fget_nt_acl","fset_nt_acl","get_nt_acl","get_nt_acl_at"]'
+ out=$(cat $PREFIX/$status_json | jq -c '."ACL Calls"|keys')
+ if [ "$expected" != "$out" ]; then
+ echo "Failed: Unexpected keys in smbstatus -jP"
+ echo "Expected: $expected"
+ echo "Output: $out"
+ return 1
+ fi
+
+ # keys in ACL Calls, fget_nt_acl
+ expected='["count","time"]'
+ out=$(cat $PREFIX/$status_json | jq -c '."ACL Calls"."fget_nt_acl"|keys')
+ if [ "$expected" != "$out" ]; then
+ echo "Failed: Unexpected keys in smbstatus -jP"
+ echo "Expected: $expected"
+ echo "Output: $out"
+ return 1
+ fi
+
+ rm $PREFIX/$status_json
+
+ return 0
+}
+
+testit "plain" \
+ test_smbstatus ||
+ failed=$(expr $failed + 1)
+
+testit "resolve_uids" \
+ test_smbstatus ||
+ failed=$(expr $failed + 1)
+
+testit "test_output" \
+ test_smbstatus_output ||
+ failed=$(expr $failed + 1)
+
+testit "test_json" \
+ test_smbstatus_json || \
+ failed=`expr $failed + 1`
+
+testit "test_json_profile" \
+ test_smbstatus_json_profile || \
+ failed=`expr $failed + 1`
+
+testok $0 $failed
diff --git a/source3/script/tests/test_smbtorture_nocrash_s3.sh b/source3/script/tests/test_smbtorture_nocrash_s3.sh
new file mode 100755
index 0000000..b6ef139
--- /dev/null
+++ b/source3/script/tests/test_smbtorture_nocrash_s3.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+. $(dirname $0)/../../../testprogs/blackbox/subunit.sh
+
+# this runs the file serving tests that are expected to pass with samba3
+
+if [ $# -lt 5 ]; then
+ cat <<EOF
+Usage: test_smbtorture_s3.sh TEST UNC USERNAME PASSWORD SMBTORTURE <smbtorture args>
+EOF
+ exit 1
+fi
+
+t="$1"
+unc="$2"
+username="$3"
+password="$4"
+SMBTORTURE="$5"
+shift 5
+ADDARGS="$*"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+panic_count_0=$(grep -c PANIC $SMBD_TEST_LOG)
+
+echo "$panic_count_0" >/tmp/look
+
+failed=0
+testit "smbtorture" $VALGRIND $SMBTORTURE $unc -U"$username"%"$password" $ADDARGS $t || failed=$(expr $failed + 1)
+
+panic_count_1=$(grep -c PANIC $SMBD_TEST_LOG)
+
+echo "$panic_count_1" >>/tmp/look
+
+testit "check_panic" test $panic_count_0 -eq $panic_count_1 || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_smbtorture_s3.sh b/source3/script/tests/test_smbtorture_s3.sh
new file mode 100755
index 0000000..4376f4a
--- /dev/null
+++ b/source3/script/tests/test_smbtorture_s3.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# this runs the file serving tests that are expected to pass with samba3
+
+if [ $# -lt 5 ]; then
+ cat <<EOF
+Usage: test_smbtorture_s3.sh TEST UNC USERNAME PASSWORD SMBTORTURE <smbtorture args>
+EOF
+ exit 1
+fi
+
+t="$1"
+unc="$2"
+username="$3"
+password="$4"
+SMBTORTURE="$5"
+shift 5
+ADDARGS="$*"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+testit "smbtorture" $VALGRIND $SMBTORTURE $unc -U"$username"%"$password" $ADDARGS $t || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_stream_dir_rename.sh b/source3/script/tests/test_stream_dir_rename.sh
new file mode 100755
index 0000000..7ac3194
--- /dev/null
+++ b/source3/script/tests/test_stream_dir_rename.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+#
+# Test a stream can rename a directory once an invalid stream path below it was requested.
+# BUG: https://bugzilla.samba.org/show_bug.cgi?id=15314
+
+if [ $# -lt 5 ]; then
+ cat <<EOF
+Usage: test_stream_dir_rename.sh SERVER USERNAME PASSWORD PREFIX SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER="${1}"
+USERNAME="${2}"
+PASSWORD="${3}"
+PREFIX="${4}"
+SMBCLIENT="${5}"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+shift 5
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+test_stream_xattr_rename()
+{
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ #
+ # Test against streams_xattr_nostrict
+ #
+ cat >$tmpfile <<EOF
+deltree stream_xattr_test
+deltree stream_xattr_test1
+mkdir stream_xattr_test
+put ${PREFIX}/smbclient_interactive_prompt_commands stream_xattr_test/file.txt
+get stream_xattr_test/file.txt:abcf
+rename stream_xattr_test stream_xattr_test1
+deltree stream_xattr_test
+deltree stream_xattr_test1
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/streams_xattr_nostrict < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret -ne 0 ]; then
+ echo "$out"
+ echo "failed rename on xattr stream test to test1 with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep "NT_STATUS_ACCESS_DENIED"
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "$out"
+ echo "failed rename on xattr stream with NT_STATUS_ACCESS_DENIED"
+ return 1
+ fi
+}
+
+testit "stream_rename" \
+ test_stream_xattr_rename ||
+ failed=$((failed + 1))
+
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_substitutions.sh b/source3/script/tests/test_substitutions.sh
new file mode 100755
index 0000000..aa0b38d
--- /dev/null
+++ b/source3/script/tests/test_substitutions.sh
@@ -0,0 +1,79 @@
+#!/bin/sh
+# Blackbox tests for substitutions
+#
+# Copyright (c) 2016 Andreas Schneider <asn@samba.org>
+
+if [ $# -lt 4 ]; then
+ cat <<EOF
+Usage: test_substitutions.sh SERVER USERNAME PASSWORD PREFIX
+EOF
+ exit 1
+fi
+
+SERVER=$1
+USERNAME=$2
+PASSWORD=$3
+PREFIX=$4
+shift 4
+failed=0
+
+samba_bindir="$BINDIR"
+samba_srcdir="$SRCDIR"
+smbclient="$samba_bindir/smbclient"
+rpcclient="$samba_bindir/rpcclient"
+
+. $samba_srcdir/testprogs/blackbox/subunit.sh
+. $samba_srcdir/testprogs/blackbox/common_test_fns.inc
+
+SMB_UNC="//$SERVER/sub_dug"
+
+test_smbclient "Test login to share with substitution (DUG)" \
+ "ls" "$SMB_UNC" "-U$USERNAME%$PASSWORD" || failed=$(expr $failed + 1)
+
+SMB_UNC="//$SERVER/sub_dug2"
+
+test_smbclient "Test login to share with substitution (Dug)" \
+ "ls" "$SMB_UNC" "-U$USERNAME%$PASSWORD" || failed=$(expr $failed + 1)
+
+SMB_UNC="//$SERVER/sub_valid_users"
+
+test_smbclient "Test login to share with substitution for valid users" \
+ "ls" "$SMB_UNC" "-U$USERNAME%$PASSWORD" || failed=$(expr $failed + 1)
+
+SMB_UNC="//$SERVER/sub_valid_users_domain"
+
+test_smbclient "Test login to share with substitution for valid user's domain" \
+ "ls" "$SMB_UNC" "-U$USERNAME%$PASSWORD" || failed=$(expr $failed + 1)
+
+SMB_UNC="//$SERVER/sub_valid_users_group"
+
+test_smbclient "Test login to share with substitution for valid user's UNIX group" \
+ "ls" "$SMB_UNC" "-U$USERNAME%$PASSWORD" || failed=$(expr $failed + 1)
+
+test_smbclient \
+ "Test for login to share with include substitution [${USERNAME}]" \
+ "ls" "//${SERVER}/${USERNAME}_share" "-U$USERNAME%$PASSWORD" ||
+ failed=$((failed + 1))
+
+test_smbclient_expect_failure \
+ "Netative test for login to share with include substitution [${DC_USERNAME}]" \
+ "ls" "//${SERVER}/${USERNAME}_share" "-U$DC_USERNAME%$DC_PASSWORD" ||
+ failed=$((failed + 1))
+
+testit_grep_count \
+ "Test for share enum with include substitution" \
+ "netname: ${USERNAME}_share" \
+ 1 \
+ ${rpcclient} "ncacn_np:${SERVER}" "-U$USERNAME%$PASSWORD" \
+ -c netshareenum ||
+ failed=$((failed + 1))
+
+testit_grep_count \
+ "Negative test for share enum with include substitution" \
+ "netname: ${USERNAME}_share" \
+ 0 \
+ ${rpcclient} "ncacn_np:${SERVER}" "-U$DC_USERNAME%$DC_PASSWORD" \
+ -c netshareenum ||
+ failed=$((failed + 1))
+
+exit $failed
diff --git a/source3/script/tests/test_success.sh b/source3/script/tests/test_success.sh
new file mode 100755
index 0000000..7ba8ddb
--- /dev/null
+++ b/source3/script/tests/test_success.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+#
+# Blackbox test that should simply succeed.
+#
+# Copyright (C) 2011 Michael Adam <obnox@samba.org>
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+test_success()
+{
+ true
+}
+
+testit "success" \
+ test_success ||
+ failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_symlink_dosmode.sh b/source3/script/tests/test_symlink_dosmode.sh
new file mode 100755
index 0000000..dd6cb6b
--- /dev/null
+++ b/source3/script/tests/test_symlink_dosmode.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+
+if [ $# -lt 7 ]; then
+ cat <<EOF
+Usage: test_symlink_dosmode.sh SERVER SERVER_IP USERNAME PASSWORD LOCAL_PATH PREFIX SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER="${1}"
+SERVER_IP="${2}"
+USERNAME="${3}"
+PASSWORD="${4}"
+LOCAL_PATH="${5}"
+PREFIX="${6}"
+SMBCLIENT="${7}"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+shift 6
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir"/subunit.sh
+
+failed=0
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+# Define the test environment/filenames.
+#
+share_test_dir="$LOCAL_PATH"
+
+rm -rf "$share_test_dir/testdir"
+
+mkdir -p "$share_test_dir/testdir/dir"
+touch "$share_test_dir/testdir/file"
+ln -s "../file" "$share_test_dir/testdir/dir/symlink"
+
+test_symlink_dosmode()
+{
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ cat >"$tmpfile" <<EOF
+ls testdir/dir/*
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/local_symlinks -I$SERVER_IP < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+ rm -f "$tmpfile"
+
+ if [ $ret != 0 ]; then
+ printf "%s\n" "$out"
+ printf "failed accessing local_symlinks with error %s\n" "$ret"
+ return 1
+ fi
+
+ mode=$(printf "%s" "$out" | awk '/symlink/ {print $2}')
+ echo "mode: $mode"
+ if [ x"$mode" != x"N" ] ; then
+ printf "Bad mode: '%s', expected 'N'\n" "$mode"
+ printf "%s\n" "$out"
+ return 1
+ fi
+ return 0
+}
+
+testit "symlink_dosmode" \
+ test_symlink_dosmode ||
+ failed=$((failed + 1))
+
+rm -rf "$share_test_dir/testdir"
+
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_symlink_rename_smb1_posix.sh b/source3/script/tests/test_symlink_rename_smb1_posix.sh
new file mode 100755
index 0000000..00acfee
--- /dev/null
+++ b/source3/script/tests/test_symlink_rename_smb1_posix.sh
@@ -0,0 +1,185 @@
+#!/bin/sh
+
+if [ $# -lt 7 ]; then
+ cat <<EOF
+Usage: test_symlink_rename_smb1_posix.sh SERVER SERVER_IP USERNAME PASSWORD LOCAL_PATH PREFIX SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER="${1}"
+SERVER_IP="${2}"
+USERNAME="${3}"
+PASSWORD="${4}"
+LOCAL_PATH="${5}"
+PREFIX="${6}"
+SMBCLIENT="${7}"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+shift 6
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir"/subunit.sh
+
+failed=0
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+# Define the test environment/filenames.
+#
+share_test_dir="$LOCAL_PATH"
+#
+# These files/directories will be created.
+#
+file_outside_share="/tmp/symlink_rename_test_file.$$"
+dir_outside_share="/tmp/symlink_rename_test_dir.$$"
+file_outside_share_noperms="/tmp/symlink_rename_test_file_noperm.$$"
+dir_outside_share_noperms="/tmp/symlink_rename_test_dir_noperm.$$"
+#
+# These two objects do not exist.
+#
+file_outside_share_noexist="/tmp/symlink_rename_test_noexist.$$"
+dir_outside_share_noexist="/tmp/symlink_rename_test_dir_noexist.$$"
+
+#
+# Cleanup function.
+#
+do_cleanup()
+{
+ (
+ #subshell.
+ cd "$share_test_dir" || return
+ rm -f "file_exists"
+ rm -f "symlink_noexist"
+ rm -f "symlink_file_outside_share"
+ rm -f "symlink_file_outside_share_noexist"
+ rm -f "symlink_dir_outside_share"
+ rm -f "symlink_dir_outside_share_noexist"
+ rm -f "symlink_file_outside_share_noperms"
+ rm -f "symlink_dir_outside_share_noperms"
+ # Links inside share.
+ rm -f "symlink_file_inside_share_noperms"
+ rm -f "file_inside_share_noperms"
+ rm -f "symlink_dir_inside_share_noperms"
+ chmod 755 "dir_inside_share_noperms"
+ rm -rf "dir_inside_share_noperms"
+ )
+ rm -f "$file_outside_share"
+ rm -rf "$dir_outside_share"
+ rm -f "$file_outside_share_noperms"
+ rm -rf "$dir_outside_share_noperms"
+}
+
+#
+# Ensure we start from a clean slate.
+#
+do_cleanup
+
+#
+# Create the test files/directories/symlinks.
+#
+# File/directory explicitly outside share.
+touch "$file_outside_share"
+mkdir "$dir_outside_share"
+# File/directory explicitly outside share with permission denied.
+touch "$file_outside_share_noperms"
+chmod 0 "$file_outside_share_noperms"
+mkdir "$dir_outside_share_noperms"
+chmod 0 "$dir_outside_share_noperms"
+#
+# Create links to these objects inside the share definition.
+(
+ #subshell.
+ cd "$share_test_dir" || return
+ # Source file for all renames. None of these should succeed.
+ touch "file_exists"
+ ln -s "noexist" "symlink_noexist"
+ ln -s "$file_outside_share" "symlink_file_outside_share"
+ ln -s "$file_outside_share_noexist" "symlink_file_outside_share_noexist"
+ ln -s "$dir_outside_share" "symlink_dir_outside_share"
+ ln -s "$dir_outside_share_noexist" "symlink_dir_outside_share_noexist"
+ ln -s "$file_outside_share_noperms" "symlink_file_outside_share_noperms"
+ ln -s "$dir_outside_share_noperms" "symlink_dir_outside_share_noperms"
+ #
+ # Create symlinks to access denied file and directory
+ # objects within the share
+ touch "file_inside_share_noperms"
+ chmod 0 "file_inside_share_noperms"
+ ln -s "file_inside_share_noperms" "symlink_file_inside_share_noperms"
+ mkdir "dir_inside_share_noperms"
+ touch "dir_inside_share_noperms/noperm_file_exists"
+ chmod 0 "dir_inside_share_noperms"
+ ln -s "dir_inside_share_noperms" "symlink_dir_inside_share_noperms"
+)
+
+#
+# smbclient function given command, path, expected error, and posix.
+#
+smbclient_expect_error()
+{
+ filecmd="$1"
+ filename1="$2"
+ filename2="$3"
+ expected_error="$4"
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ cat >"$tmpfile" <<EOF
+posix
+$filecmd $filename1 $filename2
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/local_symlinks -I$SERVER_IP -mNT1 < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+ rm -f "$tmpfile"
+
+ if [ $ret != 0 ]; then
+ printf "%s\n" "$out"
+ printf "failed accessing local_symlinks with error %s\n" "$ret"
+ return 1
+ fi
+
+ if [ "$expected_error" = "NT_STATUS_OK" ]; then
+ printf "%s" "$out" | grep -v "NT_STATUS_"
+ else
+ printf "%s" "$out" | grep "$expected_error"
+ fi
+ ret=$?
+ if [ $ret != 0 ]; then
+ printf "%s\n" "$out"
+ printf "failed - should get %s doing posix \"%s %s %s\"\n" "$expected_error" "$filecmd" "$filename1" "$filename2"
+ return 1
+ fi
+}
+
+#
+# SMB1+posix tests.
+#
+test_symlink_rename_SMB1_posix()
+{
+ #
+ # rename commands.
+ # As all the targets exist as symlinks, these should all fail.
+ #
+ smbclient_expect_error "rename" "file_exists" "symlink_noexist" "NT_STATUS_OBJECT_NAME_COLLISION" || return 1
+ smbclient_expect_error "rename" "file_exists" "symlink_file_outside_share" "NT_STATUS_OBJECT_NAME_COLLISION" || return 1
+ smbclient_expect_error "rename" "file_exists" "symlink_file_outside_share_noexist" "NT_STATUS_OBJECT_NAME_COLLISION" || return 1
+ smbclient_expect_error "rename" "file_exists" "symlink_dir_outside_share" "NT_STATUS_OBJECT_NAME_COLLISION" || return 1
+ smbclient_expect_error "rename" "file_exists" "symlink_dir_outside_share_noexist" "NT_STATUS_OBJECT_NAME_COLLISION" || return 1
+ smbclient_expect_error "rename" "file_exists" "symlink_file_outside_share_noperms" "NT_STATUS_OBJECT_NAME_COLLISION" || return 1
+ smbclient_expect_error "rename" "file_exists" "symlink_dir_outside_share_noperms" "NT_STATUS_OBJECT_NAME_COLLISION" || return 1
+ smbclient_expect_error "rename" "file_exists" "symlink_file_inside_share_noperms" "NT_STATUS_OBJECT_NAME_COLLISION" || return 1
+ smbclient_expect_error "rename" "file_exists" "symlink_dir_inside_share_noperms" "NT_STATUS_OBJECT_NAME_COLLISION" || return 1
+ return 0
+}
+
+testit "symlink_rename_SMB1_posix" \
+ test_symlink_rename_SMB1_posix ||
+ failed=$((failed + 1))
+
+#
+# Cleanup.
+do_cleanup
+
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_symlink_traversal_smb1.sh b/source3/script/tests/test_symlink_traversal_smb1.sh
new file mode 100755
index 0000000..ff38210
--- /dev/null
+++ b/source3/script/tests/test_symlink_traversal_smb1.sh
@@ -0,0 +1,262 @@
+#!/bin/sh
+
+if [ $# -lt 7 ]; then
+ cat <<EOF
+Usage: test_symlink_traversal_smb1.sh SERVER SERVER_IP USERNAME PASSWORD LOCAL_PATH PREFIX SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER="${1}"
+SERVER_IP="${2}"
+USERNAME="${3}"
+PASSWORD="${4}"
+LOCAL_PATH="${5}"
+PREFIX="${6}"
+SMBCLIENT="${7}"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+shift 6
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir"/subunit.sh
+
+failed=0
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+# Define the test environment/filenames.
+#
+share_test_dir="$LOCAL_PATH"
+#
+# These files/directories will be created.
+#
+file_outside_share="/tmp/symlink_traverse_test_file.$$"
+dir_outside_share="/tmp/symlink_traverse_test_dir.$$"
+file_outside_share_noperms="/tmp/symlink_traverse_test_file_noperm.$$"
+dir_outside_share_noperms="/tmp/symlink_traverse_test_dir_noperm.$$"
+#
+# These two objects do not exist.
+#
+file_outside_share_noexist="/tmp/symlink_traverse_test_noexist.$$"
+dir_outside_share_noexist="/tmp/symlink_traverse_test_dir_noexist.$$"
+
+#
+# Cleanup function.
+#
+do_cleanup()
+{
+ (
+ #subshell.
+ cd "$share_test_dir" || return
+ rm -f "file_exists"
+ rm -f "symlink_noexist"
+ rm -f "symlink_file_outside_share"
+ rm -f "symlink_file_outside_share_noexist"
+ rm -f "symlink_dir_outside_share"
+ rm -f "symlink_dir_outside_share_noexist"
+ rm -f "symlink_file_outside_share_noperms"
+ rm -f "symlink_dir_outside_share_noperms"
+ rm -rf "emptydir"
+ # Links inside share.
+ rm -f "symlink_file_inside_share_noperms"
+ rm -f "file_inside_share_noperms"
+ rm -f "symlink_dir_inside_share_noperms"
+ chmod 755 "dir_inside_share_noperms"
+ rm -rf "dir_inside_share_noperms"
+ )
+ rm -f "$file_outside_share"
+ rm -rf "$dir_outside_share"
+ rm -f "$file_outside_share_noperms"
+ rm -rf "$dir_outside_share_noperms"
+}
+
+#
+# Ensure we start from a clean slate.
+#
+do_cleanup
+
+#
+# Create the test files/directories/symlinks.
+#
+# File/directory explicitly outside share.
+touch "$file_outside_share"
+mkdir "$dir_outside_share"
+# File/directory explicitly outside share with permission denied.
+touch "$file_outside_share_noperms"
+chmod 0 "$file_outside_share_noperms"
+mkdir "$dir_outside_share_noperms"
+chmod 0 "$dir_outside_share_noperms"
+#
+# Create links to these objects inside the share definition.
+(
+ #subshell.
+ cd "$share_test_dir" || return
+ touch "file_exists"
+ ln -s "noexist" "symlink_noexist"
+ ln -s "$file_outside_share" "symlink_file_outside_share"
+ ln -s "$file_outside_share_noexist" "symlink_file_outside_share_noexist"
+ ln -s "$dir_outside_share" "symlink_dir_outside_share"
+ ln -s "$dir_outside_share_noexist" "symlink_dir_outside_share_noexist"
+ ln -s "$file_outside_share_noperms" "symlink_file_outside_share_noperms"
+ ln -s "$dir_outside_share_noperms" "symlink_dir_outside_share_noperms"
+ #
+ # Create the identical symlink set underneath "emptydir"
+ mkdir "emptydir"
+ (
+ #subshell
+ cd "emptydir" || return
+ touch "file_exists"
+ ln -s "noexist" "symlink_noexist"
+ ln -s "$file_outside_share" "symlink_file_outside_share"
+ ln -s "$file_outside_share_noexist" "symlink_file_outside_share_noexist"
+ ln -s "$dir_outside_share" "symlink_dir_outside_share"
+ ln -s "$dir_outside_share_noexist" "symlink_dir_outside_share_noexist"
+ ln -s "$file_outside_share_noperms" "symlink_file_outside_share_noperms"
+ ln -s "$dir_outside_share_noperms" "symlink_dir_outside_share_noperms"
+ )
+ #
+ # Create symlinks to access denied file and directory
+ # objects within the share
+ touch "file_inside_share_noperms"
+ chmod 0 "file_inside_share_noperms"
+ ln -s "file_inside_share_noperms" "symlink_file_inside_share_noperms"
+ mkdir "dir_inside_share_noperms"
+ touch "dir_inside_share_noperms/noperm_file_exists"
+ chmod 0 "dir_inside_share_noperms"
+ ln -s "dir_inside_share_noperms" "symlink_dir_inside_share_noperms"
+)
+
+#
+# smbclient function given command, path, expected error, and posix.
+#
+smbclient_expect_error()
+{
+ filecmd="$1"
+ filename1="$2"
+ filename2="$3"
+ expected_error="$4"
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ cat >"$tmpfile" <<EOF
+$filecmd $filename1 $filename2
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/local_symlinks -I$SERVER_IP -mNT1 < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+ rm -f "$tmpfile"
+
+ if [ $ret != 0 ]; then
+ printf "%s\n" "$out"
+ printf "failed accessing local_symlinks with error %s\n" "$ret"
+ return 1
+ fi
+
+ if [ "$expected_error" = "NT_STATUS_OK" ]; then
+ printf "%s" "$out" | grep -v "NT_STATUS_"
+ else
+ printf "%s" "$out" | grep "$expected_error"
+ fi
+ ret=$?
+ if [ $ret != 0 ]; then
+ printf "%s\n" "$out"
+ printf "failed - should get %s doing \"%s %s %s\"\n" "$expected_error" "$filecmd" "$filename1" "$filename2"
+ return 1
+ fi
+}
+
+#
+# SMB1 tests.
+#
+test_symlink_traversal_SMB1_onename()
+{
+ name="$1"
+ do_rename="$2"
+ #
+ # get commands.
+ #
+ smbclient_expect_error "get" "$name" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "$name/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "$name/*" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+ smbclient_expect_error "get" "$name/*/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+ # Now in subdirectory emptydir
+ smbclient_expect_error "get" "emptydir/$name" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "emptydir/$name/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "emptydir/$name/*" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+ smbclient_expect_error "get" "emptydir/$name/*/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+ #
+ # ls commands.
+ #
+ smbclient_expect_error "ls" "$name" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+ smbclient_expect_error "ls" "$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "$name/*" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "$name/*/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+ # Now in subdirectory emptydir
+ smbclient_expect_error "ls" "emptydir/$name" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+ smbclient_expect_error "ls" "emptydir/$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "emptydir/$name/*" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "emptydir/$name/*/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+
+ #
+ # del commands.
+ # smbclient internally does a cli_list, so we expect similar errors.
+ #
+ smbclient_expect_error "del" "$name" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+ smbclient_expect_error "del" "$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ # Now in subdirectory emptydir
+ smbclient_expect_error "del" "emptydir/$name" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+ smbclient_expect_error "del" "emptydir/$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+
+ if [ "$do_rename" = "do rename" ]; then
+ #
+ # rename commands.
+ #
+ smbclient_expect_error "rename" "file_exists" "$name" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "rename" "file_exists" "$name/noexist" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ # Now in subdirectory emptydir
+ smbclient_expect_error "rename" "file_exists" "emptydir/$name" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "rename" "file_exists" "emptydir/$name/noexist" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ fi
+ return 0
+}
+
+#
+# Check error code returns traversing through different
+# kinds of symlinks over SMB1.
+#
+test_symlink_traversal_SMB1()
+{
+ test_symlink_traversal_SMB1_onename "symlink_noexist" "no rename" || return 1
+ test_symlink_traversal_SMB1_onename "symlink_file_outside_share" "do rename" || return 1
+ test_symlink_traversal_SMB1_onename "symlink_dir_outside_share" "do rename" || return 1
+ test_symlink_traversal_SMB1_onename "symlink_dir_outside_share_noexist" "no rename" || return 1
+ test_symlink_traversal_SMB1_onename "symlink_file_outside_share_noperms" "do rename" || return 1
+ test_symlink_traversal_SMB1_onename "symlink_dir_outside_share_noperms" "do rename" || return 1
+ #
+ # Test paths within share with no permissions.
+ #
+ # Can't 'get' file with no perms or a symlink to it.
+ smbclient_expect_error "get" "file_inside_share_noperms" "" "NT_STATUS_ACCESS_DENIED" || return 1
+ smbclient_expect_error "get" "symlink_file_inside_share_noperms" "" "NT_STATUS_ACCESS_DENIED" || return 1
+ # But can list it and the symlink to it.
+ smbclient_expect_error "ls" "file_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "ls" "symlink_file_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+ # Can't 'get' file inside a directory with no perms or a symlink to it.
+ smbclient_expect_error "get" "dir_inside_share_noperms/noperm_file_exists" "" "NT_STATUS_ACCESS_DENIED" || return 1
+ smbclient_expect_error "get" "symlink_dir_inside_share_noperms/noperm_file_exists" "" "NT_STATUS_ACCESS_DENIED" || return 1
+ # But can list the directory with no perms and the symlink to it.
+ smbclient_expect_error "ls" "dir_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "ls" "symlink_dir_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+}
+
+testit "symlink_traversal_SMB1" \
+ test_symlink_traversal_SMB1 ||
+ failed=$((failed + 1))
+
+#
+# Cleanup.
+do_cleanup
+
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_symlink_traversal_smb1_posix.sh b/source3/script/tests/test_symlink_traversal_smb1_posix.sh
new file mode 100755
index 0000000..52d6cfb
--- /dev/null
+++ b/source3/script/tests/test_symlink_traversal_smb1_posix.sh
@@ -0,0 +1,269 @@
+#!/bin/sh
+
+if [ $# -lt 7 ]; then
+ cat <<EOF
+Usage: test_symlink_traversal_smb1_posix.sh SERVER SERVER_IP USERNAME PASSWORD LOCAL_PATH PREFIX SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER="${1}"
+SERVER_IP="${2}"
+USERNAME="${3}"
+PASSWORD="${4}"
+LOCAL_PATH="${5}"
+PREFIX="${6}"
+SMBCLIENT="${7}"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+shift 6
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir"/subunit.sh
+
+failed=0
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+# Define the test environment/filenames.
+#
+share_test_dir="$LOCAL_PATH"
+#
+# These files/directories will be created.
+#
+file_outside_share="/tmp/symlink_traverse_test_file.$$"
+dir_outside_share="/tmp/symlink_traverse_test_dir.$$"
+file_outside_share_noperms="/tmp/symlink_traverse_test_file_noperm.$$"
+dir_outside_share_noperms="/tmp/symlink_traverse_test_dir_noperm.$$"
+#
+# These two objects do not exist.
+#
+file_outside_share_noexist="/tmp/symlink_traverse_test_noexist.$$"
+dir_outside_share_noexist="/tmp/symlink_traverse_test_dir_noexist.$$"
+
+#
+# Cleanup function.
+#
+do_cleanup()
+{
+ (
+ #subshell.
+ cd "$share_test_dir" || return
+ rm -f "file_exists"
+ rm -f "symlink_noexist"
+ rm -f "symlink_file_outside_share"
+ rm -f "symlink_file_outside_share_noexist"
+ rm -f "symlink_dir_outside_share"
+ rm -f "symlink_dir_outside_share_noexist"
+ rm -f "symlink_file_outside_share_noperms"
+ rm -f "symlink_dir_outside_share_noperms"
+ rm -rf "emptydir"
+ # Links inside share.
+ rm -f "symlink_file_inside_share_noperms"
+ rm -f "file_inside_share_noperms"
+ rm -f "symlink_dir_inside_share_noperms"
+ chmod 755 "dir_inside_share_noperms"
+ rm -rf "dir_inside_share_noperms"
+ )
+ rm -f "$file_outside_share"
+ rm -rf "$dir_outside_share"
+ rm -f "$file_outside_share_noperms"
+ rm -rf "$dir_outside_share_noperms"
+}
+
+#
+# Ensure we start from a clean slate.
+#
+do_cleanup
+
+#
+# Create the test files/directories/symlinks.
+#
+# File/directory explicitly outside share.
+touch "$file_outside_share"
+mkdir "$dir_outside_share"
+# File/directory explicitly outside share with permission denied.
+touch "$file_outside_share_noperms"
+chmod 0 "$file_outside_share_noperms"
+mkdir "$dir_outside_share_noperms"
+chmod 0 "$dir_outside_share_noperms"
+#
+# Create links to these objects inside the share definition.
+(
+ #subshell.
+ cd "$share_test_dir" || return
+ touch "file_exists"
+ ln -s "noexist" "symlink_noexist"
+ ln -s "$file_outside_share" "symlink_file_outside_share"
+ ln -s "$file_outside_share_noexist" "symlink_file_outside_share_noexist"
+ ln -s "$dir_outside_share" "symlink_dir_outside_share"
+ ln -s "$dir_outside_share_noexist" "symlink_dir_outside_share_noexist"
+ ln -s "$file_outside_share_noperms" "symlink_file_outside_share_noperms"
+ ln -s "$dir_outside_share_noperms" "symlink_dir_outside_share_noperms"
+ #
+ # Create the identical symlink set underneath "emptydir"
+ mkdir "emptydir"
+ (
+ #subshell
+ cd "emptydir" || return
+ touch "file_exists"
+ ln -s "noexist" "symlink_noexist"
+ ln -s "$file_outside_share" "symlink_file_outside_share"
+ ln -s "$file_outside_share_noexist" "symlink_file_outside_share_noexist"
+ ln -s "$dir_outside_share" "symlink_dir_outside_share"
+ ln -s "$dir_outside_share_noexist" "symlink_dir_outside_share_noexist"
+ ln -s "$file_outside_share_noperms" "symlink_file_outside_share_noperms"
+ ln -s "$dir_outside_share_noperms" "symlink_dir_outside_share_noperms"
+ )
+ #
+ # Create symlinks to access denied file and directory
+ # objects within the share
+ touch "file_inside_share_noperms"
+ chmod 0 "file_inside_share_noperms"
+ ln -s "file_inside_share_noperms" "symlink_file_inside_share_noperms"
+ mkdir "dir_inside_share_noperms"
+ touch "dir_inside_share_noperms/noperm_file_exists"
+ chmod 0 "dir_inside_share_noperms"
+ ln -s "dir_inside_share_noperms" "symlink_dir_inside_share_noperms"
+)
+
+#
+# smbclient function given command, path, expected error, and posix.
+#
+smbclient_expect_error()
+{
+ filecmd="$1"
+ filename1="$2"
+ filename2="$3"
+ expected_error="$4"
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ cat >"$tmpfile" <<EOF
+posix
+$filecmd $filename1 $filename2
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/local_symlinks -I$SERVER_IP -mNT1 < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+ rm -f "$tmpfile"
+
+ if [ $ret != 0 ]; then
+ printf "%s\n" "$out"
+ printf "failed accessing local_symlinks with error %s\n" "$ret"
+ return 1
+ fi
+
+ if [ "$expected_error" = "NT_STATUS_OK" ]; then
+ printf "%s" "$out" | grep -v "NT_STATUS_"
+ else
+ printf "%s" "$out" | grep "$expected_error"
+ fi
+ ret=$?
+ if [ $ret != 0 ]; then
+ printf "%s\n" "$out"
+ printf "failed - should get %s doing posix \"%s %s %s\"\n" "$expected_error" "$filecmd" "$filename1" "$filename2"
+ return 1
+ fi
+}
+
+#
+# SMB1+posix tests.
+#
+test_symlink_traversal_SMB1_posix_onename()
+{
+ name="$1"
+ do_rename="$2"
+ #
+ # get commands.
+ #
+ # Remember in SMB1+POSIX, "*" is a perfectly valid pathname component,
+ # and symlinks can be seen, but not necessarily followed.
+ #
+ smbclient_expect_error "get" "$name" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "$name/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "$name/*" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "$name/*/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ # Now in subdirectory emptydir
+ smbclient_expect_error "get" "emptydir/$name" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "emptydir/$name/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "emptydir/$name/*" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "emptydir/$name/*/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ #
+ # ls commands.
+ #
+ smbclient_expect_error "ls" "$name" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "ls" "$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "$name/*" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "$name/*/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ # Now in subdirectory emptydir
+ smbclient_expect_error "ls" "emptydir/$name" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "ls" "emptydir/$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "emptydir/$name/*" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "emptydir/$name/*/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ #
+ # SMB1+POSIX stat commands. All symlinks can be stat'ed.
+ #
+ smbclient_expect_error "stat" "$name" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "stat" "emptydir/$name" "" "NT_STATUS_OK" || return 1
+ #
+ # del commands. Under SMB1+POSIX we can legitimately delete symlinks, so don't
+ # try and delete symlink targets, we need them for the later tests.
+ #
+ smbclient_expect_error "del" "$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ # Now in subdirectory emptydir
+ smbclient_expect_error "del" "emptydir/$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+
+ if [ "$do_rename" = "do rename" ]; then
+ #
+ # rename commands. Under SMB1+POSIX we can legitimately rename symlinks, so don't
+ # try and rename symlink targets, we need them for the later tests.
+ #
+ smbclient_expect_error "rename" "file_exists" "$name/noexist" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ # Now in subdirectory emptydir
+ smbclient_expect_error "rename" "file_exists" "emptydir/$name/noexist" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ fi
+ return 0
+}
+
+#
+# Check error code returns traversing through different
+# kinds of symlinks over SMB1+posix.
+#
+test_symlink_traversal_SMB1_posix()
+{
+ test_symlink_traversal_SMB1_posix_onename "symlink_noexist" "no rename" || return 1
+ test_symlink_traversal_SMB1_posix_onename "symlink_file_outside_share" "do rename" || return 1
+ test_symlink_traversal_SMB1_posix_onename "symlink_dir_outside_share" "do rename" || return 1
+ test_symlink_traversal_SMB1_posix_onename "symlink_dir_outside_share_noexist" "no rename" || return 1
+ test_symlink_traversal_SMB1_posix_onename "symlink_file_outside_share_noperms" "do rename" || return 1
+ test_symlink_traversal_SMB1_posix_onename "symlink_dir_outside_share_noperms" "do rename" || return 1
+ #
+ # Test paths within share with no permissions.
+ #
+ # Can't 'get' file with no perms.
+ smbclient_expect_error "get" "file_inside_share_noperms" "" "NT_STATUS_ACCESS_DENIED" || return 1
+ # In SMB1+POSIX you can't "get" a symlink at all.
+ smbclient_expect_error "get" "symlink_file_inside_share_noperms" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ # But can list it and the symlink to it.
+ smbclient_expect_error "ls" "file_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "ls" "symlink_file_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+ # Can't 'get' file inside a directory with no perms.
+ smbclient_expect_error "get" "dir_inside_share_noperms/noperm_file_exists" "" "NT_STATUS_ACCESS_DENIED" || return 1
+ # In SMB1+POSIX you can't traverse through a symlink that points to a noperm directory.
+ smbclient_expect_error "get" "symlink_dir_inside_share_noperms/noperm_file_exists" "" "NT_STATUS_ACCESS_DENIED" || return 1
+ # But can list the directory with no perms and the symlink to it.
+ smbclient_expect_error "ls" "dir_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "ls" "symlink_dir_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+}
+
+testit "symlink_traversal_SMB1_posix" \
+ test_symlink_traversal_SMB1_posix ||
+ failed=$((failed + 1))
+
+#
+# Cleanup.
+do_cleanup
+
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_symlink_traversal_smb2.sh b/source3/script/tests/test_symlink_traversal_smb2.sh
new file mode 100755
index 0000000..38719cc
--- /dev/null
+++ b/source3/script/tests/test_symlink_traversal_smb2.sh
@@ -0,0 +1,382 @@
+#!/bin/sh
+
+if [ $# -lt 7 ]; then
+ cat <<EOF
+Usage: test_symlink_traversal_smb2.sh SERVER SERVER_IP USERNAME PASSWORD LOCAL_PATH PREFIX SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER="${1}"
+SERVER_IP="${2}"
+USERNAME="${3}"
+PASSWORD="${4}"
+LOCAL_PATH="${5}"
+PREFIX="${6}"
+SMBCLIENT="${7}"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+shift 6
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir"/subunit.sh
+
+failed=0
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+# Define the test environment/filenames.
+#
+share_test_dir="$LOCAL_PATH"
+#
+# These files/directories will be created.
+#
+file_outside_share="/tmp/symlink_traverse_test_file.$$"
+dir_outside_share="/tmp/symlink_traverse_test_dir.$$"
+file_outside_share_noperms="/tmp/symlink_traverse_test_file_noperm.$$"
+dir_outside_share_noperms="/tmp/symlink_traverse_test_dir_noperm.$$"
+#
+# These two objects do not exist.
+#
+file_outside_share_noexist="/tmp/symlink_traverse_test_noexist.$$"
+dir_outside_share_noexist="/tmp/symlink_traverse_test_dir_noexist.$$"
+
+#
+# Cleanup function.
+#
+do_cleanup()
+{
+ (
+ #subshell.
+ cd "$share_test_dir" || return
+ rm -f "symlink_to_dot"
+ rm -f "file_exists"
+ rm -f "symlink_to_file_exists"
+ rm -rf "dir_exists"
+ rm -f "symlink_to_dir_exists"
+ rm -f "symlink_noexist"
+ rm -f "symlink_file_outside_share"
+ rm -f "symlink_file_outside_share_noexist"
+ rm -f "symlink_dir_outside_share"
+ rm -f "symlink_dir_outside_share_noexist"
+ rm -f "symlink_file_outside_share_noperms"
+ rm -f "symlink_dir_outside_share_noperms"
+ rm -rf "emptydir"
+ # Links inside share.
+ rm -f "symlink_file_inside_share_noperms"
+ rm -f "file_inside_share_noperms"
+ rm -f "symlink_dir_inside_share_noperms"
+ chmod 755 "dir_inside_share_noperms"
+ rm -rf "dir_inside_share_noperms"
+ )
+ rm -f "$file_outside_share"
+ rm -rf "$dir_outside_share"
+ rm -f "$file_outside_share_noperms"
+ rm -rf "$dir_outside_share_noperms"
+}
+
+#
+# Ensure we start from a clean slate.
+#
+do_cleanup
+
+#
+# Create the test files/directories/symlinks.
+#
+# File/directory explicitly outside share.
+touch "$file_outside_share"
+mkdir "$dir_outside_share"
+# File/directory explicitly outside share with permission denied.
+touch "$file_outside_share_noperms"
+chmod 0 "$file_outside_share_noperms"
+mkdir "$dir_outside_share_noperms"
+chmod 0 "$dir_outside_share_noperms"
+#
+# Create links to these objects inside the share definition.
+(
+ #subshell.
+ cd "$share_test_dir" || return
+ ln -s "." "symlink_to_dot"
+ touch "file_exists"
+ ln -s "file_exists" "symlink_to_file_exists"
+ mkdir "dir_exists"
+ ln -s "dir_exists" "symlink_to_dir_exists"
+ touch "dir_exists/subfile_exists"
+ mkdir "dir_exists/subdir_exists"
+ ln -s "noexist" "symlink_noexist"
+ ln -s "$file_outside_share" "symlink_file_outside_share"
+ ln -s "$file_outside_share_noexist" "symlink_file_outside_share_noexist"
+ ln -s "$dir_outside_share" "symlink_dir_outside_share"
+ ln -s "$dir_outside_share_noexist" "symlink_dir_outside_share_noexist"
+ ln -s "$file_outside_share_noperms" "symlink_file_outside_share_noperms"
+ ln -s "$dir_outside_share_noperms" "symlink_dir_outside_share_noperms"
+ #
+ # Create the identical symlink set underneath "emptydir"
+ mkdir "emptydir"
+ (
+ #subshell
+ cd "emptydir" || return
+ ln -s "." "symlink_to_dot"
+ touch "file_exists"
+ ln -s "file_exists" "symlink_to_file_exists"
+ mkdir "dir_exists"
+ ln -s "dir_exists" "symlink_to_dir_exists"
+ touch "dir_exists/subfile_exists"
+ mkdir "dir_exists/subdir_exists"
+ ln -s "noexist" "symlink_noexist"
+ ln -s "$file_outside_share" "symlink_file_outside_share"
+ ln -s "$file_outside_share_noexist" "symlink_file_outside_share_noexist"
+ ln -s "$dir_outside_share" "symlink_dir_outside_share"
+ ln -s "$dir_outside_share_noexist" "symlink_dir_outside_share_noexist"
+ ln -s "$file_outside_share_noperms" "symlink_file_outside_share_noperms"
+ ln -s "$dir_outside_share_noperms" "symlink_dir_outside_share_noperms"
+ )
+ #
+ # Create symlinks to access denied file and directory
+ # objects within the share
+ touch "file_inside_share_noperms"
+ chmod 0 "file_inside_share_noperms"
+ ln -s "file_inside_share_noperms" "symlink_file_inside_share_noperms"
+ mkdir "dir_inside_share_noperms"
+ touch "dir_inside_share_noperms/noperm_file_exists"
+ ln -s "dir_inside_share_noperms" "symlink_dir_inside_share_noperms"
+ mkdir "dir_inside_share_noperms/noperm_subdir_exists"
+ touch "dir_inside_share_noperms/noperm_subdir_exists/noperm_subdir_file_exists"
+ chmod 0 "dir_inside_share_noperms"
+
+ # Symlink pointing out of the share
+ ln -s "$share_test_dir"a"/etc" x
+)
+
+#
+# smbclient function given command, path, expected error, and posix.
+#
+smbclient_expect_error()
+{
+ filecmd="$1"
+ filename1="$2"
+ filename2="$3"
+ expected_error="$4"
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ cat >"$tmpfile" <<EOF
+$filecmd $filename1 $filename2
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/local_symlinks -I$SERVER_IP < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+ rm -f "$tmpfile"
+
+ if [ $ret != 0 ]; then
+ printf "%s\n" "$out"
+ printf "failed accessing local_symlinks with error %s\n" "$ret"
+ return 1
+ fi
+
+ if [ "$expected_error" = "NT_STATUS_OK" ]; then
+ printf "%s" "$out" | grep -v "NT_STATUS_"
+ else
+ printf "%s" "$out" | grep "$expected_error"
+ fi
+ ret=$?
+ if [ $ret != 0 ]; then
+ printf "%s\n" "$out"
+ printf "failed - should get %s doing \"%s %s %s\"\n" "$expected_error" "$filecmd" "$filename1" "$filename2"
+ return 1
+ fi
+}
+
+#
+# SMB2 tests.
+#
+test_symlink_traversal_SMB2_onename()
+{
+ name="$1"
+ do_rename="$2"
+ #
+ # get commands.
+ #
+ smbclient_expect_error "get" "$name" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "$name/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "$name/noexistsdir/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "$name/*" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+ smbclient_expect_error "get" "$name/*/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+ smbclient_expect_error "get" "$name/*/noexistsdir/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+ # Now in subdirectory emptydir
+ smbclient_expect_error "get" "emptydir/$name" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "emptydir/$name/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "emptydir/$name/noexistsdir/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "emptydir/$name/*" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+ smbclient_expect_error "get" "emptydir/$name/*/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+ smbclient_expect_error "get" "emptydir/$name/*/noexistsdir/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+ #
+ # ls commands.
+ #
+ smbclient_expect_error "ls" "$name" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+ smbclient_expect_error "ls" "$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "$name/noexistsdir/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "$name/*" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "$name/*/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+ smbclient_expect_error "ls" "$name/*/noexistsdir/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+ # Now in subdirectory emptydir
+ smbclient_expect_error "ls" "emptydir/$name" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+ smbclient_expect_error "ls" "emptydir/$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "emptydir/$name/noexistsdir/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "emptydir/$name/*" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "emptydir/$name/*/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+ smbclient_expect_error "ls" "emptydir/$name/*/noexistsdir/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+
+ #
+ # del commands.
+ # smbclient internally does a cli_list, so we expect similar errors.
+ #
+ smbclient_expect_error "del" "$name" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+ smbclient_expect_error "del" "$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ # Now in subdirectory emptydir
+ smbclient_expect_error "del" "emptydir/$name" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+ smbclient_expect_error "del" "emptydir/$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+
+ if [ "$do_rename" = "do rename" ]; then
+ #
+ # rename commands.
+ #
+ smbclient_expect_error "rename" "file_exists" "$name" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "rename" "file_exists" "$name/noexist" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "rename" "symlink_to_file_exists" "$name" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "rename" "symlink_to_file_exists" "$name/noexist" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "rename" "dir_exists" "$name" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "rename" "dir_exists" "$name/noexist" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "rename" "symlink_to_dir_exists" "$name" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "rename" "symlink_to_dir_exists" "$name/noexist" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ # Now in subdirectory emptydir
+ smbclient_expect_error "rename" "file_exists" "emptydir/$name" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "rename" "file_exists" "emptydir/$name/noexist" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "rename" "symlink_to_file_exists" "emptydir/$name" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "rename" "symlink_to_file_exists" "emptydir/$name/noexist" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "rename" "dir_exists" "emptydir/$name" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "rename" "dir_exists" "emptydir/$name/noexist" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "rename" "symlink_to_dir_exists" "emptydir/$name" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "rename" "symlink_to_dir_exists" "emptydir/$name/noexist" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ fi
+ return 0
+}
+
+#
+# Check error code returns traversing through different
+# kinds of symlinks over SMB2.
+#
+test_symlink_traversal_SMB2()
+{
+ test_symlink_traversal_SMB2_onename "symlink_noexist" "no rename" || return 1
+ test_symlink_traversal_SMB2_onename "symlink_file_outside_share" "do rename" || return 1
+ test_symlink_traversal_SMB2_onename "symlink_dir_outside_share" "do rename" || return 1
+ test_symlink_traversal_SMB2_onename "symlink_dir_outside_share_noexist" "no rename" || return 1
+ test_symlink_traversal_SMB2_onename "symlink_file_outside_share_noperms" "do rename" || return 1
+ test_symlink_traversal_SMB2_onename "symlink_dir_outside_share_noperms" "do rename" || return 1
+
+ # Note the share has 'follow symlinks = yes'
+ smbclient_expect_error "ls" "." "" "NT_STATUS_NO_SUCH_FILE" || return 1
+ smbclient_expect_error "ls" "noexist1" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+ smbclient_expect_error "ls" "noexist1/noexist2" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "noexist1/noexist2/noexist3" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "symlink_to_dot" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "ls" "symlink_to_dot/noexist1" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+ smbclient_expect_error "ls" "symlink_to_dot/noexist1/noexist2" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "symlink_to_dot/noexist1/noexist2/noexist3" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "file_exists" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "ls" "file_exists/noexist1" "" "NT_STATUS_NOT_A_DIRECTORY" || return 1
+ smbclient_expect_error "ls" "file_exists/noexist1/noexist2" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "file_exists/noexist1/noexist2/noexist3" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "symlink_to_file_exists" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "ls" "symlink_to_file_exists/noexist1" "" "NT_STATUS_NOT_A_DIRECTORY" || return 1
+ smbclient_expect_error "ls" "symlink_to_file_exists/noexist1/noexist2" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "symlink_to_file_exists/noexist1/noexist2/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "dir_exists" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "ls" "dir_exists/noexist1" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+ smbclient_expect_error "ls" "dir_exists/noexist1/noexist2" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "dir_exists/noexist1/noexist2/noexist3" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "dir_exists/subfile_exists" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "ls" "dir_exists/subfile_exists/noexist1" "" "NT_STATUS_NOT_A_DIRECTORY" || return 1
+ smbclient_expect_error "ls" "dir_exists/subfile_exists/noexist1/noexist2" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "dir_exists/subfile_exists/noexist1/noexist2/noexist3" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "dir_exists/subdir_exists" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "ls" "dir_exists/subdir_exists/noexist1" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+ smbclient_expect_error "ls" "dir_exists/subdir_exists/noexist1/noexist2" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "dir_exists/subdir_exists/noexist1/noexist2/noexist3" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "symlink_to_dir_exists" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "ls" "symlink_to_dir_exists/noexist1" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+ smbclient_expect_error "ls" "symlink_to_dir_exists/noexist1/noexist2" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "symlink_to_dir_exists/noexist1/noexist2/noexist3" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "symlink_to_dir_exists/subfile_exists" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "ls" "symlink_to_dir_exists/subfile_exists/noexist1" "" "NT_STATUS_NOT_A_DIRECTORY" || return 1
+ smbclient_expect_error "ls" "symlink_to_dir_exists/subfile_exists/noexist1/noexist2" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "symlink_to_dir_exists/subfile_exists/noexist1/noexist2/noexist3" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "symlink_to_dir_exists/subdir_exists" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "ls" "symlink_to_dir_exists/subdir_exists/noexist1" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+ smbclient_expect_error "ls" "symlink_to_dir_exists/subdir_exists/noexist1/noexist2" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "ls" "symlink_to_dir_exists/subdir_exists/noexist1/noexist2/noexist3" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+
+ smbclient_expect_error "get" "." "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+ smbclient_expect_error "get" "noexist1" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "noexist1/noexist2" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "symlink_to_dot" "" "NT_STATUS_FILE_IS_A_DIRECTORY" || return 1
+ smbclient_expect_error "get" "symlink_to_dot/noexist1" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "symlink_to_dot/noexist1/noexist2" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "file_exists" "$dir_outside_share/file_exists" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "get" "file_exists/noexist1" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "file_exists/noexist1/noexist2" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "symlink_to_file_exists" "$dir_outside_share/symlink_to_file_exists" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "get" "symlink_to_file_exists/noexist1" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "symlink_to_file_exists/noexist1/noexist2" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "dir_exists" "" "NT_STATUS_FILE_IS_A_DIRECTORY" || return 1
+ smbclient_expect_error "get" "dir_exists/noexist1" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "dir_exists/noexist1/noexist2" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "dir_exists/subfile_exists" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "get" "dir_exists/subfile_exists/noexist1" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "dir_exists/subfile_exists/noexist1/noexist2" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "dir_exists/subdir_exists" "" "NT_STATUS_FILE_IS_A_DIRECTORY" || return 1
+ smbclient_expect_error "get" "dir_exists/subdir_exists/noexist1" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "dir_exists/subdir_exists/noexist1/noexist2" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "symlink_to_dir_exists" "" "NT_STATUS_FILE_IS_A_DIRECTORY" || return 1
+ smbclient_expect_error "get" "symlink_to_dir_exists/noexist1" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "symlink_to_dir_exists/noexist1/noexist2" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "symlink_to_dir_exists/subfile_exists" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "get" "symlink_to_dir_exists/subfile_exists/noexist1" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "symlink_to_dir_exists/subfile_exists/noexist1/noexist2" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "symlink_to_dir_exists/subdir_exists" "" "NT_STATUS_FILE_IS_A_DIRECTORY" || return 1
+ smbclient_expect_error "get" "symlink_to_dir_exists/subdir_exists/noexist1" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "symlink_to_dir_exists/subdir_exists/noexist1/noexist2" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_expect_error "get" "x/passwd" "passwd" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+
+ #
+ # Test paths within share with no permissions.
+ #
+ # Can't 'get' file with no perms or a symlink to it.
+ smbclient_expect_error "get" "file_inside_share_noperms" "" "NT_STATUS_ACCESS_DENIED" || return 1
+ smbclient_expect_error "get" "symlink_file_inside_share_noperms" "" "NT_STATUS_ACCESS_DENIED" || return 1
+ # But can list it and the symlink to it.
+ smbclient_expect_error "ls" "file_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "ls" "symlink_file_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+ # Can't 'get' file inside a directory with no perms or a symlink to it.
+ smbclient_expect_error "get" "dir_inside_share_noperms/noperm_file_exists" "" "NT_STATUS_ACCESS_DENIED" || return 1
+ smbclient_expect_error "get" "symlink_dir_inside_share_noperms/noperm_file_exists" "" "NT_STATUS_ACCESS_DENIED" || return 1
+ # But can list the directory with no perms and the symlink to it.
+ smbclient_expect_error "ls" "dir_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+ smbclient_expect_error "ls" "symlink_dir_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+ # Check that 'get' on non existing subpaths also returns NT_STATUS_ACCESS_DENIED
+ smbclient_expect_error "get" "symlink_dir_inside_share_noperms/noperm_file_exists/_none_" "" "NT_STATUS_ACCESS_DENIED" || return 1
+ smbclient_expect_error "get" "symlink_dir_inside_share_noperms/noperm_subdir_exists/noperm_subdir_file_exists" "" "NT_STATUS_ACCESS_DENIED" || return 1
+ smbclient_expect_error "get" "symlink_dir_inside_share_noperms/noperm_subdir_exists/noperm_subdir_file_exists/_none_" "" "NT_STATUS_ACCESS_DENIED" || return 1
+}
+
+testit "symlink_traversal_SMB2" \
+ test_symlink_traversal_SMB2 ||
+ failed=$((failed + 1))
+
+#
+# Cleanup.
+do_cleanup
+
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_testparm_s3.sh b/source3/script/tests/test_testparm_s3.sh
new file mode 100755
index 0000000..a11ef85
--- /dev/null
+++ b/source3/script/tests/test_testparm_s3.sh
@@ -0,0 +1,150 @@
+#!/bin/sh
+
+# Tests for lp_load() via testparm.
+#
+# The main purpose (for now) is to test all the special handlers
+# and the macro expansions.
+
+if [ $# -lt 1 ]; then
+ cat <<EOF
+Usage: test_testparm_s3.sh LOCAL_PATH
+EOF
+ exit 1
+fi
+
+LOCAL_PATH="$1"
+
+TEMP_CONFFILE=${LOCAL_PATH}/smb.conf.tmp
+TESTPARM="$VALGRIND ${TESTPARM:-$BINDIR/testparm} --suppress-prompt --skip-logic-checks"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+test_include_expand_macro()
+{
+ MACRO=$1
+ rm -f ${TEMP_CONFFILE}
+ cat >${TEMP_CONFFILE} <<EOF
+[global]
+ include = ${TEMP_CONFFILE}.%${MACRO}
+EOF
+ ${TESTPARM} ${TEMP_CONFFILE}
+}
+
+test_one_global_option()
+{
+ OPTION="$@"
+ rm -f ${TEMP_CONFFILE}
+ cat >${TEMP_CONFFILE} <<EOF
+[global]
+ ${OPTION}
+EOF
+ ${TESTPARM} ${TEMP_CONFFILE}
+}
+
+test_copy()
+{
+ rm -f ${TEMP_CONFFILE}
+ cat >${TEMP_CONFFILE} <<EOF
+[share1]
+ path = /tmp
+ read only = no
+
+[share2]
+ copy = share1
+EOF
+ ${TESTPARM} ${TEMP_CONFFILE}
+}
+
+test_testparm_deprecated()
+{
+ name=$1
+ old_SAMBA_DEPRECATED_SUPPRESS=$SAMBA_DEPRECATED_SUPPRESS
+ SAMBA_DEPRECATED_SUPPRESS=
+ export SAMBA_DEPRECATED_SUPPRESS
+ testit_grep $name 'WARNING: The "lsaovernetlogon" option is deprecated' $VALGRIND ${TESTPARM} ${TEMP_CONFFILE} --option='lsaovernetlogon=true'
+ SAMBA_DEPRECATED_SUPPRESS=$old_SAMBA_DEPRECATED_SUPPRESS
+ export SAMBA_DEPRECATED_SUPPRESS
+}
+
+test_testparm_deprecated_suppress()
+{
+ name=$1
+ subunit_start_test "$name"
+ output=$(SAMBA_DEPRECATED_SUPPRESS=1 $VALGRIND ${TESTPARM} ${TEMP_CONFFILE} --option='lsa over netlogon = true' 2>&1)
+ status=$?
+ if [ "$status" = "0" ]; then
+ echo "$output" | grep --quiet 'WARNING: The "lsa over netlogon " option is deprecated'
+ status=$?
+ if [ "$status" = "1" ]; then
+ subunit_pass_test "$name"
+ else
+ echo $output | subunit_fail_test "$name"
+ fi
+ else
+ echo $output | subunit_fail_test "$name"
+ fi
+}
+
+testit "name resolve order = lmhosts wins host bcast" \
+ test_one_global_option "name resolve order = lmhosts wins host bcast" ||
+ failed=$(expr ${failed} + 1)
+
+testit_expect_failure "name resolve order = bad wins host bcast" \
+ test_one_global_option "name resolve order = bad wins host bcast" ||
+ failed=$(expr ${failed} + 1)
+
+testit_expect_failure "name resolve order = lmhosts bad host bcast" \
+ test_one_global_option "name resolve order = lmhosts bad host bcast" ||
+ failed=$(expr ${failed} + 1)
+
+testit_expect_failure "name resolve order = lmhosts wins bad bcast" \
+ test_one_global_option "name resolve order = lmhosts wins bad bcast" ||
+ failed=$(expr ${failed} + 1)
+
+testit_expect_failure "name resolve order = lmhosts wins host bad" \
+ test_one_global_option "name resolve order = lmhosts wins host bad" ||
+ failed=$(expr ${failed} + 1)
+
+testit "netbios name" \
+ test_one_global_option "netbios name = funky" ||
+ failed=$(expr ${failed} + 1)
+
+testit "netbios aliases" \
+ test_one_global_option "netbios aliases = funky1 funky2 funky3" ||
+ failed=$(expr ${failed} + 1)
+
+testit "netbios scope" \
+ test_one_global_option "netbios scope = abc" ||
+ failed=$(expr ${failed} + 1)
+
+testit "workgroup" \
+ test_one_global_option "workgroup = samba" ||
+ failed=$(expr ${failed} + 1)
+
+testit "display charset" \
+ test_one_global_option "display charset = UTF8" ||
+ failed=$(expr ${failed} + 1)
+
+testit "ldap debug level" \
+ test_one_global_option "ldap debug level = 7" ||
+ failed=$(expr ${failed} + 1)
+
+for LETTER in U G D I i L N M R T a d h m v w V; do
+ testit "include with %${LETTER} macro expansion" \
+ test_include_expand_macro "${LETTER}" ||
+ failed=$(expr ${failed} + 1)
+done
+
+testit "copy" \
+ test_copy ||
+ failed=$(expr ${failed} + 1)
+
+test_testparm_deprecated "test_deprecated_warning_printed"
+test_testparm_deprecated_suppress "test_deprecated_warning_suppressed"
+
+rm -f ${TEMP_CONFFILE}
+
+testok $0 ${failed}
diff --git a/source3/script/tests/test_tevent_glib_glue.sh b/source3/script/tests/test_tevent_glib_glue.sh
new file mode 100755
index 0000000..fa1d105
--- /dev/null
+++ b/source3/script/tests/test_tevent_glib_glue.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+TESTNAME="tevent_glib_glue_test"
+
+if [ ! -x $BINDIR/tevent_glib_glue_test ]; then
+ subunit_start_test "$TESTNAME"
+ subunit_skip_test "$TESTNAME" <<EOF
+Test needs glib2-devel
+EOF
+ testok $0 $failed
+fi
+
+testit "$TESTNAME" $VALGRIND $BINDIR/tevent_glib_glue_test ||
+ failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_timestamps.sh b/source3/script/tests/test_timestamps.sh
new file mode 100755
index 0000000..a158beb
--- /dev/null
+++ b/source3/script/tests/test_timestamps.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+#
+# This verifies getting and setting timestamps with non-trivial values like 0
+# and < 0 works.
+#
+
+if [ $# -lt 5 ]; then
+ echo "Usage: $0 SERVER_IP USERNAME PASSWORD PREFIX SMBCLIENT"
+ exit 1
+fi
+
+SERVER_IP="$1"
+USERNAME="$2"
+PASSWORD="$3"
+PREFIX="$4"
+SMBCLIENT="$5"
+
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+failed=0
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+export TZ=GMT
+
+setup_testfiles()
+{
+ touch -d "$(date --date=@0)" $PREFIX/time_0
+ touch -d "$(date --date=@-1)" $PREFIX/time_-1
+ touch -d "$(date --date=@-2)" $PREFIX/time_-2
+ touch -t 196801010000 $PREFIX/time_1968
+}
+
+remove_testfiles()
+{
+ rm $PREFIX/time_0
+ rm $PREFIX/time_-1
+ rm $PREFIX/time_-2
+ rm $PREFIX/time_1968
+}
+
+test_time()
+{
+ local file="$1"
+ local expected="$2"
+
+ $SMBCLIENT //$SERVER/tmp -U $USERNAME%$PASSWORD -c "allinfo $file"
+ out=$($SMBCLIENT //$SERVER/tmp -U $USERNAME%$PASSWORD -c "allinfo $file" 2>&1) || return 1
+ echo "smbclient allinfo on $file returned: \"$out\""
+
+ # Ignore create_time as that is synthesized
+ for time in access_time write_time change_time; do
+ echo "$out" | grep "$time" | grep "$expected" || {
+ echo "Expected \"$expected\", got: \"$(echo $out | grep $time)\""
+ return 1
+ }
+ done
+}
+
+#Setup
+testit "create testfiles" setup_testfiles || failed=$(expr $failed + 1)
+
+# Tests
+testit "time=0" test_time time_0 "Thu Jan 1 12:00:00 AM 1970 GMT" || failed=$(expr $failed + 1)
+testit "time=-1" test_time time_-1 "Wed Dec 31 11:59:59 PM 1969 GMT" || failed=$(expr $failed + 1)
+testit "time=-2" test_time time_-2 "Wed Dec 31 11:59:58 PM 1969 GMT" || failed=$(expr $failed + 1)
+testit "time=1968" test_time time_1968 "Mon Jan 1 12:00:00 AM 1968 GMT" || failed=$(expr $failed + 1)
+
+# Cleanup
+testit "delete testfile" remove_testfiles || failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source3/script/tests/test_user_in_sharelist.sh b/source3/script/tests/test_user_in_sharelist.sh
new file mode 100755
index 0000000..0069d6d
--- /dev/null
+++ b/source3/script/tests/test_user_in_sharelist.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+
+if [ $# -lt 2 ]; then
+ echo Usage: $0 RPCCLIENT SERVER
+ exit 1
+fi
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+RPCCLIENT="$1"; shift 1
+SERVER="$1"; shift 1
+
+"${RPCCLIENT}" "${SERVER}" -U"${USER}"%"${PASSWORD}" -c netshareenum |
+ grep "^netname: $USER\$"
+RC=$?
+testit "Verify username is listed in netshareenum due to [homes]" \
+ test $RC = 0 || failed=$((failed+1))
+
+testok $0 $failed
diff --git a/source3/script/tests/test_usernamemap.sh b/source3/script/tests/test_usernamemap.sh
new file mode 100755
index 0000000..334070e
--- /dev/null
+++ b/source3/script/tests/test_usernamemap.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# Copyright (c) 2022 Pavel Filipenský <pfilipen@redhat.com>
+#
+# Tests for "username map" smb.conf parameter for UNIX groups
+
+if [ $# -lt 2 ]; then
+ cat <<EOF
+Usage: test_usernamemap.sh SERVER SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+SMBCLIENT="$2"
+SMBCLIENT="${VALGRIND} ${SMBCLIENT}"
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "${incdir}"/subunit.sh
+
+failed=0
+
+# jackthemapper is mapped to jacknomapper, so we need jacknomapper password
+testit "jackthemapper" "${SMBCLIENT}" //"${SERVER}"/tmp -U"${SERVER}/jackthemapper%nOmApsEcrEt" -c ls || failed=$((failed + 1))
+# jacknomapper is not mapped, so we need jacknomapper password
+testit "jacknomapper" "${SMBCLIENT}" //"${SERVER}"/tmp -U"${SERVER}/jacknomapper%nOmApsEcrEt" -c ls || failed=$((failed + 1))
+
+testok "$0" "${failed}"
diff --git a/source3/script/tests/test_valid_users.sh b/source3/script/tests/test_valid_users.sh
new file mode 100755
index 0000000..659eb6a
--- /dev/null
+++ b/source3/script/tests/test_valid_users.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+#
+# Blackbox test for valid users.
+#
+
+if [ $# -lt 7 ]; then
+ cat <<EOF
+Usage: valid_users SERVER SERVER_IP DOMAIN USERNAME PASSWORD PREFIX SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER=${1}
+SERVER_IP=${2}
+DOMAIN=${3}
+USERNAME=${4}
+PASSWORD=${5}
+PREFIX=${6}
+SMBCLIENT=${7}
+shift 7
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+ADDARGS="$*"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+# Test listing a share with valid users succeeds
+test_valid_users_access()
+{
+ tmpfile=$PREFIX/smbclient.in.$$
+ prompt="foo"
+ cat >$tmpfile <<EOF
+ls
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$1" -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed accessing share with valid users with error $ret"
+
+ false
+ return
+ fi
+
+ echo "$out" | grep "$prompt" >/dev/null 2>&1
+
+ ret=$?
+ if [ $ret = 0 ]; then
+ # got the correct prompt .. succeed
+ true
+ else
+ echo "$out"
+ echo "failed listing share with valid users"
+ false
+ fi
+}
+
+testit "accessing a valid users share succeeds" \
+ test_valid_users_access valid-users-access ||
+ failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source3/script/tests/test_veto_files.sh b/source3/script/tests/test_veto_files.sh
new file mode 100755
index 0000000..201883e
--- /dev/null
+++ b/source3/script/tests/test_veto_files.sh
@@ -0,0 +1,279 @@
+#!/bin/sh
+#
+# Check smbclient cannot get a file that matches a veto files
+# parameter, or inside a directory that matches a veto files
+# parameter.
+#
+# BUG: https://bugzilla.samba.org/show_bug.cgi?id=15143
+#
+
+if [ $# -lt 6 ]; then
+ cat <<EOF
+Usage: $0 SERVER SERVER_IP USERNAME PASSWORD SHAREPATH SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER=${1}
+SERVER_IP=${2}
+USERNAME=${3}
+PASSWORD=${4}
+SHAREPATH=${5}
+SMBCLIENT=${6}
+shift 6
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+# Used by test_smbclient()
+# shellcheck disable=2034
+smbclient="$VALGRIND ${SMBCLIENT}"
+ADDARGS="$@"
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir"/subunit.sh
+. "${incdir}/common_test_fns.inc"
+
+failed=0
+
+TMPDIR=${PREFIX_ABS}/$(basename "${0}")
+mkdir -p "${TMPDIR}" || exit 1
+cd "${TMPDIR}" || exit 1
+
+#
+# Cleanup function.
+#
+do_cleanup()
+{
+ (
+ #subshell.
+ rm -rf "$SHAREPATH/dir_1"
+ rm -rf "$SHAREPATH/veto_name_dir"
+ rm -rf "$SHAREPATH/veto_name_dir\"mangle"
+ rm -f "$SHAREPATH/veto_name_file"
+ rm -f "$SHAREPATH/veto_name_file\"mangle"
+ rm -f "${SHAREPATH}/regular_file"
+ rm -f "${SHAREPATH}/.hidden_file"
+ )
+}
+
+#
+# smbclient function given path and expected error.
+#
+smbclient_get_expect_error()
+{
+ filename1="$1"
+ expected_error="$2"
+ tmpfile=${TMPDIR}/smbclient_interactive_prompt_commands
+ cat >"$tmpfile" <<EOF
+get $filename1 got_file
+quit
+EOF
+ rm -f got_file
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/veto_files -I$SERVER_IP < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+ rm -f "$tmpfile"
+ rm -f got_file
+
+ if [ $ret != 0 ]; then
+ printf "%s\n" "$out"
+ printf "failed accessing veto_files share with error %s\n" "$ret"
+ return 1
+ fi
+
+ if [ "$expected_error" = "NT_STATUS_OK" ]; then
+ printf "%s" "$out" | grep "NT_STATUS_" | wc -l | grep '^0$'
+ else
+ printf "%s" "$out" | grep "$expected_error"
+ fi
+ ret=$?
+ if [ $ret != 0 ]; then
+ printf "%s\n" "$out"
+ printf "failed - should get %s doing \"get %s got_file\"\n" "$expected_error" "$filename1"
+ return 1
+ fi
+}
+
+smbclient_create_expect_error()
+{
+ filename="$1.$$"
+ expected_error="$2"
+ tmpfile=${TMPDIR}/smbclient_interactive_prompt_commands
+ cat >"$tmpfile" <<EOF
+put $tmpfile $filename
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/veto_files -I$SERVER_IP < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+ rm -f "$tmpfile"
+ rm -f "$SHAREPATH/$filename"
+
+ if [ $ret != 0 ]; then
+ printf "%s\n" "$out"
+ printf "failed accessing veto_files share with error %s\n" "$ret"
+ return 1
+ fi
+
+ if [ "$expected_error" = "NT_STATUS_OK" ]; then
+ printf "%s" "$out" | grep -c "NT_STATUS_" && false
+ else
+ printf "%s" "$out" | grep "$expected_error"
+ fi
+ ret=$?
+ if [ $ret != 0 ]; then
+ printf "%s\n" "$out"
+ printf "failed - should get %s doing \"put %s\"\n" "$expected_error" "$filename"
+ return 1
+ fi
+}
+
+#
+# Using the share "[veto_files]" ensure we
+# cannot fetch a veto'd file or file in a veto'd directory.
+#
+test_get_veto_file()
+{
+ # toplevel
+ smbclient_get_expect_error "veto_name_file" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_get_expect_error "veto_name_dir/file_inside_dir" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_get_expect_error "veto_name_dir/testdir/file_inside_dir" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+
+ # toplevel mangle names
+ smbclient_get_expect_error "VHXE5P~M" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_get_expect_error "VF5SKC~B/file_inside_dir" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_get_expect_error "VF5SKC~B/testdir/file_inside_dir" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+
+ # depth1
+ smbclient_get_expect_error "dir1/veto_name_file" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_get_expect_error "dir1/veto_name_dir/file_inside_dir" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_get_expect_error "dir1/veto_name_dir/testdir/file_inside_dir" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+
+ # depth1 mangle names
+ smbclient_get_expect_error "dir1/VHXE5P~M" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_get_expect_error "dir1/VF5SKC~B/file_inside_dir" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_get_expect_error "dir1/VF5SKC~B/testdir/file_inside_dir" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+
+ # depth2
+ smbclient_get_expect_error "dir1/dir2/veto_name_file" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_get_expect_error "dir1/dir2/veto_name_dir/file_inside_dir" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_get_expect_error "dir1/dir2/veto_name_dir/testdir/file_inside_dir" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+
+ # depth2 mangle names
+ smbclient_get_expect_error "dir1/dir2/VHXE5P~M" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_get_expect_error "dir1/dir2/VF5SKC~B/file_inside_dir" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_get_expect_error "dir1/dir2/VF5SKC~B/testdir/file_inside_dir" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+
+ # depth3
+ smbclient_get_expect_error "dir1/dir2/dir3/veto_name_file" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_get_expect_error "dir1/dir2/dir3/veto_name_dir/file_inside_dir" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_get_expect_error "dir1/dir2/dir3/veto_name_dir/testdir/file_inside_dir" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+
+ # depth3 mangle names
+ smbclient_get_expect_error "dir1/dir2/dir3/VHXE5P~M" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_get_expect_error "dir1/dir2/dir3/VF5SKC~B/file_inside_dir" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_get_expect_error "dir1/dir2/dir3/VF5SKC~B/testdir/file_inside_dir" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+
+ return 0
+}
+
+test_create_veto_file()
+{
+ # Test creating files
+ smbclient_create_expect_error "veto_name_file" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+ smbclient_create_expect_error "veto_name_dir/file_inside_dir" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+ smbclient_create_expect_error "dir1/veto_name_file" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+
+ return 0
+}
+
+do_cleanup
+
+echo "regular_file" > "${SHAREPATH}/regular_file"
+echo "hidden_file" > "${SHAREPATH}/.hidden_file"
+
+test_smbclient "download regular file" \
+ "get regular_file" "//${SERVER}/veto_files_nohidden" \
+ -U"${USERNAME}%${PASSWORD}" ||
+ failed=$((failed + 1))
+rm -f regular_file
+test_smbclient_expect_failure "hidden file can't be downloaded" \
+ "get .hidden_file" "//${SERVER}/veto_files_nohidden" \
+ -U"${USERNAME}%${PASSWORD}" ||
+ failed=$((failed + 1))
+test_smbclient "list files" \
+ "ls" "//${SERVER}/veto_files_nohidden" \
+ -U"${USERNAME}%${PASSWORD}" ||
+ failed=$((failed + 1))
+
+do_cleanup
+
+# Using hash2, veto_name_file\"mangle == VHXE5P~M
+# Using hash2, veto_name_dir\"mangle == VF5SKC~B
+
+# I think a depth of 3 should be enough.
+# toplevel
+touch "$SHAREPATH/veto_name_file"
+mkdir "$SHAREPATH/veto_name_dir"
+touch "$SHAREPATH/veto_name_dir/file_inside_dir"
+mkdir "$SHAREPATH/veto_name_dir/testdir"
+touch "$SHAREPATH/veto_name_dir/testdir/file_inside_dir"
+# toplevel mangle names.
+touch "$SHAREPATH/veto_name_file\"mangle"
+mkdir "$SHAREPATH/veto_name_dir\"mangle"
+touch "$SHAREPATH/veto_name_dir\"mangle/file_inside_dir"
+mkdir "$SHAREPATH/veto_name_dir\"mangle/testdir"
+touch "$SHAREPATH/veto_name_dir\"mangle/testdir/file_inside_dir"
+
+#depth1
+mkdir "$SHAREPATH/dir1"
+touch "$SHAREPATH/dir1/veto_name_file"
+mkdir "$SHAREPATH/dir1/veto_name_dir"
+touch "$SHAREPATH/dir1/veto_name_dir/file_inside_dir"
+mkdir "$SHAREPATH/dir1/veto_name_dir/testdir"
+touch "$SHAREPATH/dir1/veto_name_dir/testdir/file_inside_dir"
+# depth1 mangle names.
+touch "$SHAREPATH/dir1/veto_name_file\"mangle"
+mkdir "$SHAREPATH/dir1/veto_name_dir\"mangle"
+touch "$SHAREPATH/dir1/veto_name_dir\"mangle/file_inside_dir"
+mkdir "$SHAREPATH/dir1/veto_name_dir\"mangle/testdir"
+touch "$SHAREPATH/dir1/veto_name_dir\"mangle/testdir/file_inside_dir"
+
+#depth2
+mkdir "$SHAREPATH/dir1/dir2"
+touch "$SHAREPATH/dir1/dir2/veto_name_file"
+mkdir "$SHAREPATH/dir1/dir2/veto_name_dir"
+touch "$SHAREPATH/dir1/dir2/veto_name_dir/file_inside_dir"
+mkdir "$SHAREPATH/dir1/dir2/veto_name_dir/testdir"
+touch "$SHAREPATH/dir1/dir2/veto_name_dir/testdir/file_inside_dir"
+# depth2 mangle names.
+touch "$SHAREPATH/dir1/dir2/veto_name_file\"mangle"
+mkdir "$SHAREPATH/dir1/dir2/veto_name_dir\"mangle"
+touch "$SHAREPATH/dir1/dir2/veto_name_dir\"mangle/file_inside_dir"
+mkdir "$SHAREPATH/dir1/dir2/veto_name_dir\"mangle/testdir"
+touch "$SHAREPATH/dir1/dir2/veto_name_dir\"mangle/testdir/file_inside_dir"
+
+#depth3
+mkdir "$SHAREPATH/dir1/dir2/dir3"
+touch "$SHAREPATH/dir1/dir2/dir3/veto_name_file"
+mkdir "$SHAREPATH/dir1/dir2/dir3/veto_name_dir"
+touch "$SHAREPATH/dir1/dir2/dir3/veto_name_dir/file_inside_dir"
+mkdir "$SHAREPATH/dir1/dir2/dir3/veto_name_dir/testdir"
+touch "$SHAREPATH/dir1/dir2/dir3/veto_name_dir/testdir/file_inside_dir"
+# depth3 mangle names.
+touch "$SHAREPATH/dir1/dir2/dir3/veto_name_file\"mangle"
+mkdir "$SHAREPATH/dir1/dir2/dir3/veto_name_dir\"mangle"
+touch "$SHAREPATH/dir1/dir2/dir3/veto_name_dir\"mangle/file_inside_dir"
+mkdir "$SHAREPATH/dir1/dir2/dir3/veto_name_dir\"mangle/testdir"
+touch "$SHAREPATH/dir1/dir2/dir3/veto_name_dir\"mangle/testdir/file_inside_dir"
+
+testit "create_veto_file" test_create_veto_file || failed=$((failed + 1))
+testit "get_veto_file" test_get_veto_file || failed=$(("$failed" + 1))
+
+do_cleanup
+
+cd "${PREFIX_ABS}" && rm -rf ${TMPDIR}
+
+exit "$failed"
diff --git a/source3/script/tests/test_veto_rmdir.sh b/source3/script/tests/test_veto_rmdir.sh
new file mode 100755
index 0000000..4d7db9d
--- /dev/null
+++ b/source3/script/tests/test_veto_rmdir.sh
@@ -0,0 +1,217 @@
+#!/bin/sh
+#
+# Check smbclient can (or cannot) delete a directory containing veto files.
+# BUG: https://bugzilla.samba.org/show_bug.cgi?id=14878
+#
+
+if [ $# -lt 6 ]; then
+ cat <<EOF
+Usage: $0 SERVER SERVER_IP USERNAME PASSWORD SHAREPATH SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER=${1}
+SERVER_IP=${2}
+USERNAME=${3}
+PASSWORD=${4}
+SHAREPATH=${5}
+SMBCLIENT=${6}
+shift 6
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+ADDARGS="$@"
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir"/subunit.sh
+
+failed=0
+
+rmdir_path="$SHAREPATH/dir"
+
+test_veto_nodelete_rmdir()
+{
+ local veto_path="$rmdir_path/veto_name1"
+ local msdfs_link_path="$rmdir_path/dfs_link"
+ local tmpfile=$PREFIX/smbclient.in.$$
+
+ # Create rmdir directory.
+ mkdir -p "$rmdir_path"
+ # Create veto file underneath.
+ touch "$veto_path"
+ # Create msdfs link underneath.
+ ln -s "msdfs:$SERVER_IP\\ro-tmp" "$msdfs_link_path"
+
+ cat >"$tmpfile" <<EOF
+cd dir
+ls
+quit
+EOF
+
+ local cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT //$SERVER/veto_files_nodelete -U$USERNAME%$PASSWORD $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+
+ # Check for smbclient error.
+ if [ $ret != 0 ]; then
+ echo "Failed accessing share veto_files_nodelete - $ret"
+ echo "$out"
+ return 1
+ fi
+
+ # We should only see the dfs_link file.
+ echo "$out" | grep dfs_link
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "Failed to see dfs_link in share veto_files_nodelete"
+ echo "$out"
+ return 1
+ fi
+
+ # Now remove the dfs_link file.
+ rm -rf "$msdfs_link_path"
+
+ # Try and remove the directory, should fail with NT_STATUS_DIRECTORY_NOT_EMPTY.
+ cat >"$tmpfile" <<EOF
+rd dir
+quit
+EOF
+
+ local cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT //$SERVER/veto_files_nodelete -U$USERNAME%$PASSWORD $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+
+ # Check for smbclient error.
+ if [ $ret != 0 ]; then
+ echo "Failed accessing share veto_files_nodelete - $ret"
+ echo "$out"
+ return 1
+ fi
+
+ # We should get NT_STATUS_DIRECTORY_NOT_EMPTY.
+ echo "$out" | grep NT_STATUS_DIRECTORY_NOT_EMPTY
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "Failed to get error NT_STATUS_DIRECTORY_NOT_EMPTY in share veto_files_nodelete"
+ echo "$out"
+ return 1
+ fi
+
+ # remove the veto file - directory should now be empty.
+ rm -rf "$veto_path"
+
+ # Try and remove the directory, should now succeed.
+ cat >"$tmpfile" <<EOF
+rd dir
+quit
+EOF
+
+ local cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT //$SERVER/veto_files_nodelete -U$USERNAME%$PASSWORD $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+
+ # Check for smbclient error.
+ if [ $ret != 0 ]; then
+ echo "Failed accessing share veto_files_nodelete - $ret"
+ echo "$out"
+ return 1
+ fi
+
+ # We should get no NT_STATUS_ errors.
+ echo "$out" | grep NT_STATUS_
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "Got error NT_STATUS_ in share veto_files_nodelete"
+ echo "$out"
+ return 1
+ fi
+
+ return 0
+}
+
+test_veto_delete_rmdir()
+{
+ local veto_path="$rmdir_path/veto_name1"
+ local msdfs_link_path="$rmdir_path/dfs_link"
+ local tmpfile=$PREFIX/smbclient.in.$$
+
+ # Create rmdir directory.
+ mkdir -p "$rmdir_path"
+ # Create veto file underneath.
+ touch "$veto_path"
+ # Create msdfs link underneath.
+ ln -s "msdfs:$SERVER_IP\\ro-tmp" "$msdfs_link_path"
+
+ cat >"$tmpfile" <<EOF
+cd dir
+ls
+quit
+EOF
+
+ local cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT //$SERVER/veto_files_delete -U$USERNAME%$PASSWORD $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+
+ # Check for smbclient error.
+ if [ $ret != 0 ]; then
+ echo "Failed accessing share veto_files_delete - $ret"
+ echo "$out"
+ return 1
+ fi
+
+ # We should only see the dfs_link file.
+ echo "$out" | grep dfs_link
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "Failed to see dfs_link in share veto_files_delete"
+ echo "$out"
+ return 1
+ fi
+
+ # Now remove the dfs_link file.
+ rm -rf "$msdfs_link_path"
+
+ # Try and remove the directory, should now succeed.
+ cat >"$tmpfile" <<EOF
+rd dir
+quit
+EOF
+
+ local cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT //$SERVER/veto_files_delete -U$USERNAME%$PASSWORD $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+
+ # Check for smbclient error.
+ if [ $ret != 0 ]; then
+ echo "Failed accessing share veto_files_delete - $ret"
+ echo "$out"
+ return 1
+ fi
+
+ # We should get no NT_STATUS_ errors.
+ echo "$out" | grep NT_STATUS_
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "Got error NT_STATUS_ in share veto_files_delete"
+ echo "$out"
+ return 1
+ fi
+
+ return 0
+}
+
+testit "rmdir cannot delete directory containing a veto file" \
+ test_veto_nodelete_rmdir || failed=$(expr "$failed" + 1)
+
+rm -rf "$rmdir_path"
+
+testit "rmdir can delete directory containing a veto file" \
+ test_veto_delete_rmdir || failed=$(expr "$failed" + 1)
+
+rm -rf "$rmdir_path"
+
+exit "$failed"
diff --git a/source3/script/tests/test_virus_scanner.sh b/source3/script/tests/test_virus_scanner.sh
new file mode 100755
index 0000000..83b50df
--- /dev/null
+++ b/source3/script/tests/test_virus_scanner.sh
@@ -0,0 +1,135 @@
+#!/bin/sh
+# Copyright (c) 2022 Pavel Filipenský <pfilipen@redhat.com>
+# shellcheck disable=1091
+
+if [ $# -lt 4 ]; then
+ cat <<EOF
+Usage: $0 SERVER_IP SHARE LOCAL_PATH SMBCLIENT
+EOF
+ exit 1
+fi
+
+SERVER_IP=${1}
+SHARE=${2}
+LOCAL_PATH=${3}
+SMBCLIENT=${4}
+
+SMBCLIENT="${VALGRIND} ${SMBCLIENT}"
+
+failed=0
+sharedir="${LOCAL_PATH}/${SHARE}"
+
+incdir="$(dirname "$0")/../../../testprogs/blackbox"
+. "${incdir}/subunit.sh"
+
+check_infected_read()
+{
+ rm -rf "${sharedir:?}"/*
+
+ if ! mkdir "${sharedir}/read1"; then
+ echo "ERROR: Cannot create ${sharedir}/read1"
+ return 1
+ fi
+
+ if ! mkdir "${sharedir}/read1/read2"; then
+ echo "ERROR: Cannot create ${sharedir}/read1/read2"
+ return 1
+ fi
+
+ if ! touch "${sharedir}/read1/read2/infected.txt"; then
+ echo "ERROR: Cannot create ${sharedir}/read1/read2/infected.txt"
+ return 1
+ fi
+
+ ${SMBCLIENT} "//${SERVER_IP}/${SHARE}" -U"${USER}"%"${PASSWORD}" -c "get read1/read2/infected.txt ${sharedir}/read1/read2/infected.download.txt"
+
+ # check that virusfilter:rename prefix/suffix was added
+ if [ ! -f "${sharedir}/read1/read2/virusfilter.infected.txt.infected" ]; then
+ echo "ERROR: ${sharedir}/read1/read2/virusfilter.infected.txt.infected is missing."
+ return 1
+ fi
+
+ # check that file was not downloaded
+ if [ -f "${sharedir}/read1/read2/infected.download.txt" ]; then
+ echo "ERROR: {sharedir}/read1/read2/infected.download.txt should not exist."
+ return 1
+ fi
+
+ rm -rf "${sharedir:?}"/*
+ return 0
+}
+
+check_infected_write()
+{
+ rm -rf "${sharedir:?}"/*
+ smbfile=infected.upload.txt
+ smbfilerenamed="virusfilter.${smbfile}.infected"
+
+ # non empty file is needed
+ # vsf_virusfilter performs a scan only if fsp->fsp_flags.modified
+ if ! echo "Hello Virus!" >"${sharedir}/infected.txt"; then
+ echo "ERROR: Cannot create ${sharedir}/infected.txt"
+ return 1
+ fi
+
+ ${SMBCLIENT} "//${SERVER_IP}/${SHARE}" -U"${USER}"%"${PASSWORD}" -c "put ${sharedir}/infected.txt ${smbfile}"
+
+ # check that virusfilter:rename prefix/suffix was added
+ if [ ! -f "${sharedir}/${smbfilerenamed}" ]; then
+ echo "ERROR: ${sharedir}/${smbfilerenamed} is missing."
+ return 1
+ fi
+
+ # check that file was not uploaded
+ if [ -f "${sharedir}/infected.upload.txt" ]; then
+ echo "ERROR: {sharedir}/${smbfile} should not exist."
+ return 1
+ fi
+
+ return 0
+}
+
+check_healthy_read()
+{
+ rm -rf "${sharedir:?}"/*
+
+ if ! echo "Hello Samba!" >"${sharedir}/healthy.txt"; then
+ echo "ERROR: Cannot create ${sharedir}/healthy.txt"
+ return 1
+ fi
+
+ ${SMBCLIENT} //"${SERVER_IP}"/"${SHARE}" -U"${USER}"%"${PASSWORD}" -c "get healthy.txt ${sharedir}/healthy.download.txt"
+
+ if ! cmp "${sharedir}/healthy.txt" "${sharedir}/healthy.download.txt"; then
+ echo "ERROR: cmp ${sharedir}/healthy.txt ${sharedir}/healthy.download.txt FAILED"
+ return 1
+ fi
+
+ return 0
+}
+
+check_healthy_write()
+{
+ rm -rf "${sharedir:?}"/*
+
+ if ! echo "Hello Samba!" >"${sharedir}/healthy.txt"; then
+ echo "ERROR: Cannot create ${sharedir}/healthy.txt"
+ return 1
+ fi
+
+ ${SMBCLIENT} //"${SERVER_IP}"/"${SHARE}" -U"${USER}"%"${PASSWORD}" -c "put ${sharedir}/healthy.txt healthy.upload.txt"
+
+ if ! cmp "${sharedir}/healthy.txt" "${sharedir}/healthy.upload.txt"; then
+ echo "ERROR: cmp ${sharedir}/healthy.txt ${sharedir}/healthy.upload.txt FAILED"
+ return 1
+ fi
+
+ return 0
+}
+
+testit "check_infected_read" check_infected_read || failed=$((failed + 1))
+testit "check_infected_write" check_infected_write || failed=$((failed + 1))
+testit "check_healthy_read" check_healthy_read || failed=$((failed + 1))
+testit "check_healthy_write" check_healthy_write || failed=$((failed + 1))
+
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_volume_serial_number.sh b/source3/script/tests/test_volume_serial_number.sh
new file mode 100755
index 0000000..b156d70
--- /dev/null
+++ b/source3/script/tests/test_volume_serial_number.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# This verifies setting the volume serial number parameter for a share works.
+#
+
+if [ $# -lt 5 ]; then
+ echo "Usage: $0 SERVER_IP USERNAME PASSWORD SHARENAME SMBCLIENT"
+ exit 1
+fi
+
+SERVER_IP="$1"
+USERNAME="$2"
+PASSWORD="$3"
+SHARENAME="$4"
+SMBCLIENT="$5"
+
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+failed=0
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir/subunit.sh"
+
+test_serial_number() {
+
+ output=$($SMBCLIENT "//$SERVER_IP/$SHARENAME" -U "$USERNAME%$PASSWORD" -c "volume") || return 1
+ echo "smbclient volume on $SHARENAME returned: \"$output\""
+
+ expected="0xdeadbeef"
+ echo "$output" | grep $expected || {
+ echo "Expected output containing \"$expected\", got: \"$output\""
+ return 1
+ }
+}
+
+testit "volume serial number for share $SHARENAME" test_serial_number || failed=$((failed+1))
+
+exit "$failed"
diff --git a/source3/script/tests/test_wbinfo_lookuprids_cache.sh b/source3/script/tests/test_wbinfo_lookuprids_cache.sh
new file mode 100755
index 0000000..abb078b
--- /dev/null
+++ b/source3/script/tests/test_wbinfo_lookuprids_cache.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+WBINFO="$VALGRIND ${WBINFO:-$BINDIR/wbinfo}"
+samba_tdbtool=tdbtool
+if test -x $BINDIR/tdbtool; then
+ samba_tdbtool=$BINDIR/tdbtool
+fi
+TDBTOOL="${TDBTOOL:-$samba_tdbtool}"
+
+samba_tdbdump=tdbdump
+if test -x $BINDIR/tdbdump; then
+ samba_tdbdump=$BINDIR/tdbdump
+fi
+TDBDUMP="${TDBDUMP:-$samba_tdbdump}"
+
+NET="$VALGRIND ${NET:-$BINDIR/net}"
+
+cache="$LOCK_DIR"/winbindd_cache.tdb
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+testit "flush" "$NET" "cache" "flush" || failed=$(expr $failed + 1)
+testit "lookuprids1" "$WBINFO" "-R" "512,12345" || failed=$(expr $failed + 1)
+
+key=$("$TDBDUMP" "$cache" | grep ^key.*NDR.*/16/ | cut -d\" -f2)
+
+testit "delete" "$TDBTOOL" "$cache" delete "$key"
+testit "lookuprids2" "$WBINFO" "-R" "512,12345" || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_wbinfo_sids2xids.sh b/source3/script/tests/test_wbinfo_sids2xids.sh
new file mode 100755
index 0000000..b07aebf
--- /dev/null
+++ b/source3/script/tests/test_wbinfo_sids2xids.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+WBINFO="$VALGRIND ${WBINFO:-$BINDIR/wbinfo} $CONFIGURATION"
+NET="$VALGRIND ${NET:-$BINDIR/net} $CONFIGURATION"
+TEST_INT=$(dirname $0)/test_wbinfo_sids2xids_int.py
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+testit "sids2xids" ${TEST_INT} ${WBINFO} ${NET} || failed=$(expr $failed + 1)
+
+testok $0 $failed
diff --git a/source3/script/tests/test_wbinfo_sids2xids_int.py b/source3/script/tests/test_wbinfo_sids2xids_int.py
new file mode 100755
index 0000000..4f2715c
--- /dev/null
+++ b/source3/script/tests/test_wbinfo_sids2xids_int.py
@@ -0,0 +1,147 @@
+#!/usr/bin/env python3
+
+import sys
+import os
+import subprocess
+from samba.common import get_string
+
+
+if len(sys.argv) != 3:
+ print("Usage: test_wbinfo_sids2xids_int.py wbinfo net")
+ sys.exit(1)
+
+wbinfo = sys.argv[1]
+netcmd = sys.argv[2]
+
+
+def run(cmd):
+ """
+ Run a cmd, return bytes str for py2 and unicode str for py3.
+
+ NOTE: subprocess api always return bytes, in both py2 and py3.
+ """
+ output = subprocess.check_output(cmd).strip()
+ return get_string(output)
+
+
+def flush_cache(sids=None, uids=None, gids=None):
+ if sids is None:
+ sids = []
+ if uids is None:
+ uids = []
+ if gids is None:
+ gids = []
+
+ for sid in sids:
+ os.system(netcmd + (" cache del IDMAP/SID2XID/%s" % (sid)))
+ for uid in uids:
+ os.system(netcmd + (" cache del IDMAP/UID2SID/%s" % (uid)))
+ for gid in gids:
+ os.system(netcmd + (" cache del IDMAP/GID2SID/%s" % (gid)))
+
+
+def fill_cache(inids, idtype='gid'):
+ for inid in inids:
+ if inid is None:
+ continue
+ run([wbinfo, '--%s-to-sid=%s' % (idtype, inid)])
+
+
+domain = run([wbinfo, "--own-domain"])
+domsid = run([wbinfo, "-n", domain + "/"])
+domsid = domsid.split(' ')[0]
+
+# print domain
+# print domsid
+
+sids = [domsid + '-512', 'S-1-5-32-545', domsid + '-513', 'S-1-1-0', 'S-1-3-1', 'S-1-5-1']
+
+flush_cache(sids=sids)
+
+sids2xids = run([wbinfo, '--sids-to-unix-ids=' + ','.join(sids)])
+
+gids = []
+uids = []
+idtypes = []
+
+for line in sids2xids.split('\n'):
+ result = line.split(' ')[2:]
+ idtypes.append(result[0])
+
+ gid = None
+ uid = None
+ if result[0] == 'gid':
+ gid = result[1]
+ elif result[0] == 'uid':
+ uid = result[1]
+ elif result[0] == 'uid/gid':
+ gid = result[1]
+ uid = result[1]
+
+ if gid == '-1':
+ gid = ''
+ gids.append(gid)
+
+ if uid == '-1':
+ uid = ''
+ uids.append(uid)
+
+# Check the list produced by the sids-to-xids call with the
+# singular variant (sid-to-xid) for each sid in turn.
+
+
+def check_singular(sids, ids, idtype='gid'):
+ i = 0
+ for sid in sids:
+ if ids[i] is None:
+ continue
+
+ outid = run([wbinfo, '--sid-to-%s' % idtype, sid])
+ if outid != ids[i]:
+ print("Expected %s, got %s\n" % (outid, ids[i]))
+ flush_cache(sids=sids, uids=uids, gids=gids)
+ sys.exit(1)
+ i += 1
+
+# Check the list produced by the sids-to-xids call with the
+# multiple variant (sid-to-xid) for each sid in turn.
+
+
+def check_multiple(sids, idtypes):
+ sids2xids = run([wbinfo, '--sids-to-unix-ids=' + ','.join(sids)])
+ # print sids2xids
+ i = 0
+ for line in sids2xids.split('\n'):
+ result = line.split(' ')[2:]
+
+ if result[0] != idtypes[i]:
+ print("Expected %s, got %s\n" % (idtypes[i], result[0]))
+ flush_cache(sids=sids, uids=uids, gids=gids)
+ sys.exit(1)
+ i += 1
+
+
+# first round: with filled cache via sid-to-id
+check_singular(sids, gids, 'gid')
+check_singular(sids, uids, 'uid')
+
+# second round: with empty cache
+flush_cache(sids=sids, gids=gids)
+check_singular(sids, gids, 'gid')
+flush_cache(sids=sids, uids=uids)
+check_singular(sids, uids, 'uid')
+
+# third round: with filled cache via uid-to-sid
+flush_cache(sids=uids, uids=uids)
+fill_cache(uids, 'uid')
+check_multiple(sids, idtypes)
+
+# fourth round: with filled cache via gid-to-sid
+flush_cache(sids=sids, gids=gids)
+fill_cache(gids, 'gid')
+check_multiple(sids, idtypes)
+
+# flush the cache so any incorrect mappings don't break other tests
+flush_cache(sids=sids, uids=uids, gids=gids)
+
+sys.exit(0)
diff --git a/source3/script/tests/test_wbinfo_u_large_ad.sh b/source3/script/tests/test_wbinfo_u_large_ad.sh
new file mode 100755
index 0000000..ab5f0ca
--- /dev/null
+++ b/source3/script/tests/test_wbinfo_u_large_ad.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+LDBMODIFY="$VALGRIND ${LDBMODIFY:-$BINDIR/ldbmodify} $CONFIGURATION"
+LDBSEARCH="$VALGRIND ${LDBSEARCH:-$BINDIR/ldbsearch} $CONFIGURATION"
+WBINFO="$VALGRIND ${WBINFO:-$BINDIR/wbinfo} $CONFIGURATION"
+
+NUM_USERS=1234
+
+BASE_DN=$($LDBSEARCH -H ldap://$DC_SERVER -b "" --scope=base defaultNamingContext | awk '/^defaultNamingContext/ {print $2}')
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+seq -w 1 "$NUM_USERS" |
+ xargs -INUM echo -e "dn:cn=large_ad_NUM,cn=users,$BASE_DN\nchangetype:add\nobjectclass:user\nsamaccountname:large_ad_NUM\n" |
+ $LDBMODIFY -H ldap://$DC_SERVER -U "$DOMAIN\Administrator%$DC_PASSWORD"
+
+testit_grep_count \
+ "Make sure $NUM_USERS $DOMAIN users are returned" \
+ "$DOMAIN/large_ad_" \
+ "$NUM_USERS" \
+ ${WBINFO} -u || failed=$(expr $failed + 1)
+
+seq -w 1 "$NUM_USERS" |
+ xargs -INUM echo -e "dn:cn=large_ad_NUM,cn=users,$BASE_DN\nchangetype:delete\n" |
+ $LDBMODIFY -H ldap://$DC_SERVER -U "$DOMAIN\Administrator%$DC_PASSWORD"
+
+testok $0 $failed
diff --git a/source3/script/tests/test_winbind_call_depth_trace.sh b/source3/script/tests/test_winbind_call_depth_trace.sh
new file mode 100755
index 0000000..6d978be
--- /dev/null
+++ b/source3/script/tests/test_winbind_call_depth_trace.sh
@@ -0,0 +1,113 @@
+#!/bin/sh
+
+# Copyright (c) Pavel Filipenský <pfilipensky@samba.org>
+# License: GPLv3
+
+if [ $# -lt 4 ]; then
+ echo "Usage: test_winbind_call_depth_trace SMBCONTROL CONFIGURATION PREFIX TESTENV"
+ exit 1
+fi
+
+SMBCONTROL="${1}"
+CONFIGURATION=${2}
+PREFIX="${3}"
+TESTENV="${4}"
+shift 4
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir"/subunit.sh
+
+failed=0
+
+PREFIX_ABS="$(readlink -f "${PREFIX}")"
+# Strip from TESTENV the ':local' if present
+TESTENV_SUBDIR=${TESTENV%:*}
+
+LOGFILE="${PREFIX_ABS}/${TESTENV_SUBDIR}/logs/log.winbindd"
+# Add support for "WINBINDD_DONT_LOG_STDOUT=1"
+if [ ! -r "${LOGFILE}" ]; then
+ TEST_LOGFILE="${PREFIX_ABS}/${TESTENV_SUBDIR}/winbindd_test.log"
+ subunit_start_test "test winbind call depth trace"
+ subunit_skip_test "test winbind call depth trace" <<EOF
+Test is skipped, we need $LOGFILE but have only $TEST_LOGFILE which is missing debug headers (they are not printed to stdout).
+EOF
+ exit 0
+fi
+
+saved_level=1
+
+get_winbind_loglevel()
+{
+ s1=$(${SMBCONTROL} "${CONFIGURATION}" winbind debuglevel)
+ # We need to get the all level from output like this:
+ # "PID 664474: all:1 tdb:1 printdrivers:1 lanman:1 smb:1 rpc_parse:1 rpc_srv:1 rpc_cli:1 passdb:1 sam:1..."
+ # 1. remove PID 664474:
+ s2=${s1#PID*: }
+ # "all:1 tdb:1 printdrivers:1 lanman:1 smb:1 rpc_parse:1 rpc_srv:1 rpc_cli:1 passdb"
+ # 2. remove " tdb:1 printdrivers:1 ..."
+ s3=${s2%% *}
+ # "all:1"
+ # 3. remove "all:"
+ saved_level=${s3#all:}
+}
+
+# Example of trace line
+# [2023/01/25 00:20:33.307038, 5, pid=535581, effective(0, 0), real(0, 0), class=winbind, traceid=78, depth=4] ../../source3/winbindd/wb_group_members.c:310(wb_group_members_send)
+test_winbind_call_depth_trace()
+{
+ get_winbind_loglevel
+
+ # If loglevel < 10, set it to 10.
+ if [ "$saved_level" -lt 10 ]; then
+ ${SMBCONTROL} "${CONFIGURATION}" winbind debug 10
+ fi
+
+ COUNT1=$(grep -c wb_group_members_send "$LOGFILE")
+
+ id ADDOMAIN/alice
+ ret=$?
+
+ # Restore loglevel, if it was changed.
+ if [ "$saved_level" -lt 10 ]; then
+ ${SMBCONTROL} "${CONFIGURATION}" winbind debug "$saved_level"
+ fi
+
+ if [ $ret != 0 ]; then
+ echo "Command 'id ADDOMAIN/alice' failed!"
+ return 1
+ fi
+
+ # Check that there are more lines with wb_group_members_send
+ COUNT2=$(grep -c wb_group_members_send "$LOGFILE")
+ if [ "$COUNT1" -eq "$COUNT2" ]; then
+ echo "The number of the trace lines in $LOGFILE has not increased."
+ return 1
+ fi
+
+ # Test that the depth of last line with 'wb_group_members_send' is: depth=4
+ COUNT3=$(grep wb_group_members_send "$LOGFILE" | tail -1 | grep -c depth=4)
+ if [ "$COUNT3" -ne 1 ]; then
+ echo "The last line with wb_group_members_send should have depth=4."
+ return 1
+ fi
+
+ # Test that the indentation of the line below last 'wb_group_members_send' is indented by 2+4*4 spaces:
+ COUNT4=$(grep -A1 wb_group_members_send "$LOGFILE" | tail -1| grep -c '^ WB command group_members start')
+ if [ "$COUNT4" -ne 1 ]; then
+ echo "The line after the last line with wb_group_members_send should be indented by 18 spaces."
+ return 1
+ fi
+
+ return 0
+}
+
+case ${TESTENV} in
+ad_member*)
+ ;;
+*)
+ echo "Test is for ad_member only, but called for ${TESTENV}." | subunit_fail_test "test winbind call depth trace"
+ exit 1;
+esac
+
+testit "test winbind call depth trace" test_winbind_call_depth_trace || failed=$((failed + 1))
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_winbind_ignore_domains.sh b/source3/script/tests/test_winbind_ignore_domains.sh
new file mode 100755
index 0000000..1454eca
--- /dev/null
+++ b/source3/script/tests/test_winbind_ignore_domains.sh
@@ -0,0 +1,106 @@
+#!/bin/sh
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+. $incdir/common_test_fns.inc
+
+failed=0
+
+smbclient="$BINDIR/smbclient"
+smbcontrol="$BINDIR/smbcontrol"
+ldbmodify="$BINDIR/ldbmodify"
+ldbsearch="$BINDIR/ldbsearch"
+wbinfo="$BINDIR/wbinfo"
+global_inject_conf=$(dirname $SMB_CONF_PATH)/global_inject.conf
+SERVER_FQDN=$(echo "$SERVER.$REALM" | awk '{print tolower($0)}')
+
+TRUST_BASE_DN=$($ldbsearch -H ldap://$TRUST_SERVER -b "" -s base defaultNamingContext | awk '/^defaultNamingContext/ {print $2}')
+if [ $? -ne 0 ]; then
+ echo "Could not find trusted base DN" | subunit_fail_test "test_idmap_ad"
+ exit 1
+fi
+
+#
+# Add POSIX ids to trusted domain
+#
+add_posix_ids()
+{
+ cat <<EOF | $ldbmodify -H ldap://$TRUST_SERVER \
+ -U "$TRUST_DOMAIN\Administrator%$TRUST_PASSWORD"
+dn: CN=Administrator,CN=Users,$TRUST_BASE_DN
+changetype: modify
+add: uidNumber
+uidNumber: 2500000
+EOF
+
+ cat <<EOF | $ldbmodify -H ldap://$TRUST_SERVER \
+ -U "$TRUST_DOMAIN\Administrator%$TRUST_PASSWORD"
+dn: CN=Domain Users,CN=Users,$TRUST_BASE_DN
+changetype: modify
+add: gidNumber
+gidNumber: 2500001
+EOF
+
+ cat <<EOF | $ldbmodify -H ldap://$TRUST_SERVER \
+ -U "$TRUST_DOMAIN\Administrator%$TRUST_PASSWORD"
+dn: CN=Domain Admins,CN=Users,$TRUST_BASE_DN
+changetype: modify
+add: gidNumber
+gidNumber: 2500002
+EOF
+}
+
+#
+# Remove POSIX ids from trusted domain
+#
+remove_posix_ids()
+{
+ cat <<EOF | $ldbmodify -H ldap://$TRUST_SERVER \
+ -U "$TRUST_DOMAIN\Administrator%$TRUST_PASSWORD"
+dn: CN=Administrator,CN=Users,$TRUST_BASE_DN
+changetype: modify
+delete: uidNumber
+uidNumber: 2500000
+EOF
+
+ cat <<EOF | $ldbmodify -H ldap://$TRUST_SERVER \
+ -U "$TRUST_DOMAIN\Administrator%$TRUST_PASSWORD"
+dn: CN=Domain Users,CN=Users,$TRUST_BASE_DN
+changetype: modify
+delete: gidNumber
+gidNumber: 2500001
+EOF
+
+ cat <<EOF | $ldbmodify -H ldap://$TRUST_SERVER \
+ -U "$TRUST_DOMAIN\Administrator%$TRUST_PASSWORD"
+dn: CN=Domain Admins,CN=Users,$TRUST_BASE_DN
+changetype: modify
+delete: gidNumber
+gidNumber: 2500002
+EOF
+}
+
+add_posix_ids
+
+echo "" >$global_inject_conf
+$smbcontrol winbindd reload-config
+$wbinfo -p
+
+test_smbclient "test_winbind_ignore_domains_ok_ntlm_ip" "ls" "//$SERVER_IP/tmp" -U $TRUST_DOMAIN/$TRUST_USERNAME%$TRUST_PASSWORD || failed=$(expr $failed + 1)
+test_smbclient "test_winbind_ignore_domains_ok_ntlm_fqdn" "ls" "//$SERVER_FQDN/tmp" -U $TRUST_DOMAIN/$TRUST_USERNAME%$TRUST_PASSWORD || failed=$(expr $failed + 1)
+test_smbclient "test_winbind_ignore_domains_ok_krb5" "ls" "//$SERVER_FQDN/tmp" -U $TRUST_USERNAME@$TRUST_REALM%$TRUST_PASSWORD -k || failed=$(expr $failed + 1)
+
+echo "winbind:ignore domains = $TRUST_DOMAIN" >$global_inject_conf
+$smbcontrol winbindd reload-config
+$wbinfo -p
+
+test_smbclient_expect_failure "test_winbind_ignore_domains_fail_ntlm_ip" "ls" "//$SERVER_IP/tmp" -U $TRUST_DOMAIN/$TRUST_USERNAME%$TRUST_PASSWORD || failed=$(expr $failed + 1)
+test_smbclient_expect_failure "test_winbind_ignore_domains_fail_ntlm_fqdn" "ls" "//$SERVER_FQDN/tmp" -U $TRUST_DOMAIN/$TRUST_USERNAME%$TRUST_PASSWORD || failed=$(expr $failed + 1)
+test_smbclient_expect_failure "test_winbind_ignore_domains_fail_krb5" "ls" "//$SERVER_FQDN/tmp" -U $TRUST_USERNAME@$TRUST_REALM%$TRUST_PASSWORD -k || failed=$(expr $failed + 1)
+
+echo "" >$global_inject_conf
+$smbcontrol winbindd reload-config
+$wbinfo -p
+remove_posix_ids
+
+testok $0 $failed
diff --git a/source3/script/tests/test_worm.sh b/source3/script/tests/test_worm.sh
new file mode 100755
index 0000000..f96c8ec
--- /dev/null
+++ b/source3/script/tests/test_worm.sh
@@ -0,0 +1,121 @@
+#!/bin/sh
+
+if [ $# -lt 7 ]; then
+ cat <<EOF
+Usage: test_worm.sh SERVER SERVER_IP USERNAME PASSWORD LOCAL_PATH PREFIX SMBCLIENT ADDARGS
+EOF
+ exit 1
+fi
+
+SERVER="${1}"
+SERVER_IP="${2}"
+USERNAME="${3}"
+PASSWORD="${4}"
+LOCAL_PATH="${5}"
+PREFIX="${6}"
+SMBCLIENT="${7}"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+shift 7
+ADDARGS="$*"
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir"/subunit.sh
+
+failed=0
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+# Define the test environment/filenames.
+#
+share_test_dir="$LOCAL_PATH"
+
+#
+# Cleanup function.
+#
+do_cleanup()
+{
+ (
+ #subshell.
+ cd "$share_test_dir" || return
+ rm -f must-be-deleted must-not-be-deleted must-be-deleted-after-ctime-refresh
+ )
+ rm -f $tmpfile
+}
+
+#
+# Ensure we start from a clean slate.
+#
+do_cleanup
+
+tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+
+test_worm()
+{
+ # use echo because helo scripts don't support variables
+ echo "
+put $tmpfile must-be-deleted
+put $tmpfile must-be-deleted-after-ctime-refresh
+put $tmpfile must-not-be-deleted
+del must-be-deleted
+quit" > $tmpfile
+ # make sure the directory is not too old for worm:
+ touch $share_test_dir
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/worm -I$SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+ rm -f "$tmpfile"
+
+ if [ $ret != 0 ]; then
+ printf "%s\n" "$out"
+ printf "failed worm smbclient run with error %s\n" "$ret"
+ return 1
+ fi
+ test -e $share_test_dir/must-be-deleted && {
+ printf "$0: ERROR: must-be-deleted was NOT deleted\n"
+ return 1
+ }
+
+ # now sleep grace_period (1s) and check if worm works properly:
+ sleep 1
+ echo "
+posix
+chmod 700 must-not-be-deleted
+del must-not-be-deleted
+del must-be-deleted-after-ctime-refresh
+quit" > $tmpfile
+ # make sure the directory itself is not too old for worm:
+ touch $share_test_dir
+ # set a fresh ctime by doing a chmod:
+ chmod 644 $share_test_dir/must-be-deleted-after-ctime-refresh
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/worm -I$SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ test -e $share_test_dir/must-not-be-deleted || {
+ printf "$0: ERROR: must-not-be-deleted WAS deleted\n"
+ return 1
+ }
+ # if we're not root, return here:
+ test "$UID" = "0" || {
+ return 0
+ }
+
+ test -e $share_test_dir/must-be-deleted-after-ctime-refresh && {
+ printf "$0: ERROR: must-be-deleted-after-ctime-refresh was NOT deleted\n"
+ return 1
+ }
+ return 0
+}
+
+
+testit "worm" \
+ test_worm ||
+ failed=$((failed + 1))
+
+#
+# Cleanup.
+do_cleanup
+
+testok "$0" "$failed"
diff --git a/source3/script/tests/test_zero_data.sh b/source3/script/tests/test_zero_data.sh
new file mode 100755
index 0000000..62ba856
--- /dev/null
+++ b/source3/script/tests/test_zero_data.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+#
+# Verify that smbtorture tests for manually testing ZERO_DATA
+#
+# Copyright (C) 2019 Christof Schmitt
+
+if [ $# -lt 4 ]; then
+ cat <<EOF
+Usage: test_zero_data.sh SERVER_IP USERNAME PASSWORD LOCAL_PATH
+EOF
+ exit 1
+fi
+
+SERVER=${1}
+USERNAME=${2}
+PASSWORD=${3}
+LOCAL_PATH=${4}
+
+. $(dirname $0)/../../../testprogs/blackbox/subunit.sh
+failed=0
+
+cd $SELFTEST_TMPDIR || exit 1
+
+TESTDIR=$LOCAL_PATH/zero_data
+
+mkdir -p $TESTDIR
+chmod 777 p $TESTDIR
+
+dd if=/dev/urandom of=$TESTDIR/testfile bs=1024 count=128
+chmod 777 $TESTDIR/testfile
+
+alloc_kb=$(du -k $TESTDIR/testfile | sed -e 's/\t.*//')
+testit "check allocation before zero-data" test $alloc_kb -eq 128 ||
+ failed=$(expr $failed + 1)
+
+testit "set-sparse" $VALGRIND $BINDIR/smbtorture //$SERVER_IP/tmp \
+ -U$USERNAME%$PASSWORD smb2.set-sparse-ioctl \
+ --option=torture:filename=zero_data/testfile ||
+ failed=$(expr $failed + 1)
+
+testit "zero-data" $VALGRIND $BINDIR/smbtorture //$SERVER_IP/tmp \
+ -U$USERNAME%$PASSWORD smb2.zero-data-ioctl \
+ --option=torture:filename=zero_data/testfile \
+ --option=torture:offset=0 \
+ --option=torture:beyond_final_zero=131072 ||
+ failed=$(expr $failed + 1)
+
+alloc_kb=$(du -k $TESTDIR/testfile | sed -e 's/\t.*//')
+testit "check allocation after zero-data" test $alloc_kb -eq 0 ||
+ failed=$(expr $failed + 1)
+
+rm -rf $TESTDIR
+
+testok $0 $failed
diff --git a/source3/script/tests/test_zero_readsize.sh b/source3/script/tests/test_zero_readsize.sh
new file mode 100755
index 0000000..f859599
--- /dev/null
+++ b/source3/script/tests/test_zero_readsize.sh
@@ -0,0 +1,101 @@
+#!/usr/bin/env bash
+#
+# Test setting smb2 max read = 0.
+#
+# BUG: https://bugzilla.samba.org/show_bug.cgi?id=15306
+#
+
+if [ $# -lt 6 ]; then
+ cat <<EOF
+Usage: $0 SERVERCONFFILE SMBCLIENT SMBCONTROL SERVER SHARE PREFIX
+EOF
+ exit 1
+fi
+
+CONF=${1}
+shift 1
+SMBCLIENT=${1}
+shift 1
+SMBCONTROL=${1}
+shift 1
+SERVER=${1}
+shift 1
+SHARE=${1}
+shift 1
+PREFIX=${1}
+shift 1
+
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+ADDARGS="$@"
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir"/subunit.sh
+
+failed=0
+
+#
+# Setup function
+#
+do_setup()
+{
+ rm -f "${PREFIX}/zero_read_testfile"
+ rm -f "${PREFIX}/zero_read_testfile_get"
+ dd if=/dev/zero of="${PREFIX}/zero_read_testfile" bs=1024 count=1
+ global_inject_conf="$(dirname "${SERVERCONFFILE}")/global_inject.conf"
+ echo "smb2 max read = 0" >"$global_inject_conf"
+ ${SMBCONTROL} ${CONF} smbd reload-config
+}
+
+do_cleanup()
+{
+ rm -f "${PREFIX}/zero_read_testfile"
+ rm -f "${PREFIX}/zero_read_testfile_get"
+ global_inject_conf="$(dirname "${SERVERCONFFILE}")/global_inject.conf"
+ rm "$global_inject_conf"
+ ${SMBCONTROL} ${CONF} smbd reload-config
+}
+
+test_smb2_zero_readsize()
+{
+ local tmpfile="$PREFIX/smbclient.in.$$"
+
+ cat >"$tmpfile" <<EOF
+lcd $PREFIX
+put zero_read_testfile zero_read_testfile_put
+get zero_read_testfile_put zero_read_testfile_get
+del zero_read_testfile_put
+quit
+EOF
+
+ local cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT //$SERVER/$SHARE -U$USERNAME%$PASSWORD $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+
+ # Check for smbclient error.
+ # We should have failed the protocol negotiation, returning 1.
+ if [ $ret != 1 ]; then
+ echo "smbclient protocol negotiation succeeded (should have failed) zero read testfile $ret"
+ echo "$out"
+ return 1
+ fi
+
+ # We should get NT_STATUS_INVALID_NETWORK_RESPONSE
+ echo "$out" | grep NT_STATUS_INVALID_NETWORK_RESPONSE
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "Should get NT_STATUS_INVALID_NETWORK_RESPONSE"
+ echo "$out"
+ return 1
+ fi
+ rm "$tmpfile"
+ return 0
+}
+
+do_setup
+
+testit "smb2_zero_readsize" test_smb2_zero_readsize || failed=$((failed + 1))
+
+do_cleanup
+
+testok "$0" "$failed"
diff --git a/source3/script/tests/timelimit.c b/source3/script/tests/timelimit.c
new file mode 100644
index 0000000..886256c
--- /dev/null
+++ b/source3/script/tests/timelimit.c
@@ -0,0 +1,102 @@
+/* run a command with a limited timeout
+ tridge@samba.org, June 2005
+ metze@samba.org, March 2006
+
+ attempt to be as portable as possible (fighting posix all the way)
+*/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+static pid_t child_pid;
+
+static void usage(void)
+{
+ printf("usage: timelimit <time> <command>\n");
+ printf(" SIGUSR1 - passes SIGTERM to command's process group\n");
+ printf(" SIGALRM - passes SIGTERM to command's process group\n");
+ printf(" after 5s SIGKILL will be passed and exit(1)\n");
+ printf(" SIGTERM - passes SIGTERM to command's process group\n");
+ printf(" after 1s SIGKILL will be passed and exit(1)\n");
+}
+
+static void sig_alrm_kill(int sig)
+{
+ fprintf(stderr, "\nMaximum time expired in timelimit - killing\n");
+ kill(-child_pid, SIGKILL);
+ exit(1);
+}
+
+static void sig_alrm_term(int sig)
+{
+ kill(-child_pid, SIGTERM);
+ alarm(5);
+ signal(SIGALRM, sig_alrm_kill);
+}
+
+static void sig_term(int sig)
+{
+ kill(-child_pid, SIGTERM);
+ alarm(1);
+ signal(SIGALRM, sig_alrm_kill);
+}
+
+static void sig_usr1(int sig)
+{
+ kill(-child_pid, SIGTERM);
+}
+
+static void new_process_group(void)
+{
+ if (setpgid(0,0) == -1) {
+ perror("setpgid");
+ exit(1);
+ }
+}
+
+
+int main(int argc, char *argv[])
+{
+ int maxtime, ret=1;
+
+ if (argc < 3) {
+ usage();
+ exit(1);
+ }
+
+ maxtime = atoi(argv[1]);
+
+ child_pid = fork();
+ if (child_pid == 0) {
+ new_process_group();
+ execvp(argv[2], argv+2);
+ perror(argv[2]);
+ exit(1);
+ }
+
+ signal(SIGTERM, sig_term);
+ signal(SIGINT, sig_term);
+ signal(SIGQUIT, sig_term);
+ signal(SIGUSR1, sig_usr1);
+ signal(SIGALRM, sig_alrm_term);
+ alarm(maxtime);
+
+ do {
+ int status;
+ pid_t pid = wait(&status);
+ if (pid != -1) {
+ ret = WEXITSTATUS(status);
+ } else if (errno == ECHILD) {
+ break;
+ }
+ } while (1);
+
+ kill(-child_pid, SIGKILL);
+
+ exit(ret);
+}
diff --git a/source3/script/tests/vfstest-acl/run.sh b/source3/script/tests/vfstest-acl/run.sh
new file mode 100755
index 0000000..eb32a95
--- /dev/null
+++ b/source3/script/tests/vfstest-acl/run.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+if [ $# -lt 2 ]; then
+ cat <<EOF
+Usage: run.sh VFSTEST PREFIX
+EOF
+ exit 1
+fi
+
+TESTBASE=$(dirname $0)
+VFSTEST=$1
+PREFIX=$2
+shift 2
+ADDARGS="$*"
+
+VFSTEST_PREFIX=vfstest
+VFSTEST_TMPDIR=$(mktemp -d ${PREFIX}/${VFSTEST_PREFIX}_XXXXXX)
+
+incdir=$(dirname $0)/../../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+cd $VFSTEST_TMPDIR || exit 1
+
+test_vfstest()
+{
+ cmd='$VFSTEST -f $TESTBASE/vfstest.cmd $ADDARGS '
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "command failed"
+ false
+ return
+ fi
+
+ echo "$out" | grep "NT_STATUS_ACCESS_DENIED" >/dev/null 2>&1
+
+ if [ $? = 0 ]; then
+ # got ACCESS_DENIED .. fail
+ echo vfstest got NT_STATUS_ACCESS_DENIED
+ false
+ else
+ true
+ fi
+}
+
+testit "vfstest" test_vfstest || failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source3/script/tests/vfstest-acl/vfstest.cmd b/source3/script/tests/vfstest-acl/vfstest.cmd
new file mode 100644
index 0000000..6168671
--- /dev/null
+++ b/source3/script/tests/vfstest-acl/vfstest.cmd
@@ -0,0 +1,15 @@
+connect
+open x RC 0700
+sys_acl_get_file . 0
+sys_acl_get_file . 1
+get_nt_acl .
+set_nt_acl . G:DAD:P(A;OICI;0x001f01ff;;;BA)(A;OICI;0x001200a9;;;SO)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)
+get_nt_acl .
+sys_acl_get_file . 0
+sys_acl_get_file . 1
+get_nt_acl x
+sys_acl_get_file x 0
+set_nt_acl x G:DAD:P(A;OICI;0x001f01ff;;;BA)(A;OICI;0x001200a9;;;SO)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)
+get_nt_acl x
+sys_acl_get_file x 0
+
diff --git a/source3/script/tests/vfstest-catia/run.sh b/source3/script/tests/vfstest-catia/run.sh
new file mode 100755
index 0000000..aca2a60
--- /dev/null
+++ b/source3/script/tests/vfstest-catia/run.sh
@@ -0,0 +1,102 @@
+#!/bin/sh
+if [ $# -lt 2 ]; then
+ cat <<EOF
+Usage: run.sh VFSTEST PREFIX
+EOF
+ exit 1
+fi
+
+TESTBASE=$(dirname $0)
+VFSTEST=$1
+PREFIX=$2
+shift 2
+ADDARGS="$*"
+
+VFSTEST_PREFIX=vfstest
+VFSTEST_TMPDIR=$(mktemp -d ${PREFIX}/${VFSTEST_PREFIX}_XXXXXX)
+
+# We could pass in the --option=... via tests.py as ADDARGS
+# Atm i've chosen to specify them here:
+
+MYARGS1="--option=vfsobjects=catia"
+MYARGS2="--option=catia:mappings=0x22:0xa8,0x2a:0xa4,0x2f:0xf8,0x3a:0xf7,0x3c:0xab,0x3e:0xbb,0x3f:0xbf,0x5c:0xff,0x7c:0xa6,0x20:0xb1"
+
+# vars for the translation test:
+# a) here for unix-to-windows test
+UNIX_FILE="a\\a:a*a?a<a>a|a"
+# translated window file name
+WIN_FILE="aÿa÷a¤a¿a«a»a¦a"
+
+# b) here for windows-to-unix test
+WIN_DIR="dir_aÿa÷a¤a¿a«a»a¦a"
+# translated unix directory name
+UNIX_DIR="dir_a\a:a*a?a<a>a|a"
+
+incdir=$(dirname $0)/../../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+cd $VFSTEST_TMPDIR || exit 1
+
+# create unix file in tmpdir
+touch $UNIX_FILE || exit 1
+
+# test "translate" unix-to-windows
+test_vfstest()
+{
+ cmd='$VFSTEST --debug-stdout -f $TESTBASE/vfstest.cmd $MYARGS1 $MYARGS2 $ADDARGS '
+ out=$(eval $cmd)
+ ret=$?
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "command failed"
+ false
+ return
+ fi
+
+ echo "$out" | grep $WIN_FILE >/dev/null 2>&1
+
+ if [ $? = 0 ]; then
+ echo "ALL IS WORKING"
+ true
+ else
+ false
+ fi
+}
+
+# test the mkdir call with special windows chars
+# and then check the created unix directory name
+test_vfstest_dir()
+{
+ cmd='$VFSTEST -f $TESTBASE/vfstest1.cmd $MYARGS1 $MYARGS2 $ADDARGS '
+ out=$(eval $cmd)
+ ret=$?
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "command failed"
+ false
+ return
+ fi
+
+ NUM=$(find $UNIX_DIR | wc -l)
+ if [ $NUM -ne 1 ]; then
+ echo "Cannot find $UNIX_DIR"
+ false
+ else
+ true
+ fi
+}
+
+testit "vfstest_catia" test_vfstest || failed=$(expr $failed + 1)
+
+if [ $failed = 0 ]; then
+ testit "vfstest1_catia" test_vfstest_dir || failed=$(expr $failed + 1)
+fi
+
+# Cleanup: remove tempdir
+rm -R $VFSTEST_TMPDIR
+
+exit $failed
diff --git a/source3/script/tests/vfstest-catia/vfstest.cmd b/source3/script/tests/vfstest-catia/vfstest.cmd
new file mode 100644
index 0000000..5acecbc
--- /dev/null
+++ b/source3/script/tests/vfstest-catia/vfstest.cmd
@@ -0,0 +1,2 @@
+connect
+translate_name a\a:a*a?a<a>a|a
diff --git a/source3/script/tests/vfstest-catia/vfstest1.cmd b/source3/script/tests/vfstest-catia/vfstest1.cmd
new file mode 100644
index 0000000..ef56159
--- /dev/null
+++ b/source3/script/tests/vfstest-catia/vfstest1.cmd
@@ -0,0 +1,2 @@
+connect
+mkdir dir_aÿa÷a¤a¿a«a»a¦a
diff --git a/source3/script/tests/wb_pad.sh b/source3/script/tests/wb_pad.sh
new file mode 100755
index 0000000..f4dded6
--- /dev/null
+++ b/source3/script/tests/wb_pad.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+tempdir=$(mktemp -d /tmp/wb_padXXXXXX)
+test -n "$tempdir" || exit 1
+cat >>$tempdir/wb_pad.c <<_EOF
+#include "nsswitch/winbind_client.h"
+
+int main(int argc, const char **argv)
+{
+ struct winbindd_request req;
+ struct winbindd_response resp;
+
+ if (argc != 2) {
+ printf("usage: %s [req|resp]\n", argv[0]);
+ return 0;
+ }
+
+ if (strcmp(argv[1], "req") == 0) {
+ printf("%d\n", (uint32_t)sizeof(req));
+ }
+ if (strcmp(argv[1], "resp") == 0) {
+ printf("%d\n", (uint32_t)sizeof(resp));
+ }
+
+ return 0;
+}
+_EOF
+
+cleanup()
+{
+ rm -f $tempdir/wb_pad_32 $tempdir/wb_pad_64 $tempdir/wb_pad.c
+ rmdir $tempdir
+}
+
+cflags="-I. -I../ -I./../lib/replace -Iinclude"
+${CC:-gcc} -m32 $RPM_OPT_FLAGS $CFLAGS -o $tempdir/wb_pad_32 $cflags $tempdir/wb_pad.c
+if [ $? -ne 0 ]; then
+ cleanup
+ exit 1
+fi
+${CC:-gcc} -m64 $RPM_OPT_FLAGS $CFLAGS -o $tempdir/wb_pad_64 $cflags $tempdir/wb_pad.c
+if [ $? -ne 0 ]; then
+ cleanup
+ exit 1
+fi
+
+out_64_req=$($tempdir/wb_pad_64 req)
+out_64_resp=$($tempdir/wb_pad_64 resp)
+out_32_req=$($tempdir/wb_pad_32 req)
+out_32_resp=$($tempdir/wb_pad_32 resp)
+
+cleanup
+
+if test "$out_64_req" != "$out_32_req"; then
+ echo "winbind request size differs!"
+ echo "64bit: $out_64_req"
+ echo "32bit: $out_32_req"
+ exit 1
+fi
+
+if test "$out_64_resp" != "$out_32_resp"; then
+ echo "winbind response size differs!"
+ echo "64bit: $out_64_resp"
+ echo "32bit: $out_32_resp"
+ exit 1
+fi
+
+exit 0
diff --git a/source3/script/tests/xattr-tdb-1/run.sh b/source3/script/tests/xattr-tdb-1/run.sh
new file mode 100755
index 0000000..eb32a95
--- /dev/null
+++ b/source3/script/tests/xattr-tdb-1/run.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+if [ $# -lt 2 ]; then
+ cat <<EOF
+Usage: run.sh VFSTEST PREFIX
+EOF
+ exit 1
+fi
+
+TESTBASE=$(dirname $0)
+VFSTEST=$1
+PREFIX=$2
+shift 2
+ADDARGS="$*"
+
+VFSTEST_PREFIX=vfstest
+VFSTEST_TMPDIR=$(mktemp -d ${PREFIX}/${VFSTEST_PREFIX}_XXXXXX)
+
+incdir=$(dirname $0)/../../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+cd $VFSTEST_TMPDIR || exit 1
+
+test_vfstest()
+{
+ cmd='$VFSTEST -f $TESTBASE/vfstest.cmd $ADDARGS '
+ out=$(eval $cmd)
+ ret=$?
+ rm -f $tmpfile
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "command failed"
+ false
+ return
+ fi
+
+ echo "$out" | grep "NT_STATUS_ACCESS_DENIED" >/dev/null 2>&1
+
+ if [ $? = 0 ]; then
+ # got ACCESS_DENIED .. fail
+ echo vfstest got NT_STATUS_ACCESS_DENIED
+ false
+ else
+ true
+ fi
+}
+
+testit "vfstest" test_vfstest || failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source3/script/tests/xattr-tdb-1/vfstest.cmd b/source3/script/tests/xattr-tdb-1/vfstest.cmd
new file mode 100644
index 0000000..5eb7158
--- /dev/null
+++ b/source3/script/tests/xattr-tdb-1/vfstest.cmd
@@ -0,0 +1,6 @@
+connect
+open x RC 0700
+setxattr x y z
+listxattr x
+stat x
+unlink x
diff --git a/source3/script/updatesmbpasswd.sh b/source3/script/updatesmbpasswd.sh
new file mode 100755
index 0000000..1d7e0d7
--- /dev/null
+++ b/source3/script/updatesmbpasswd.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+nawk 'BEGIN {FS=":"}
+{
+ if( $0 ~ "^#" ) {
+ print $0
+ } else if( (length($4) == 32) && (($4 ~ "^[0-9A-F]*$") || ($4 ~ "^[X]*$") || ( $4 ~ "^[*]*$"))) {
+ print $0
+ } else {
+ printf( "%s:%s:%s:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:", $1, $2, $3);
+ for(i = 4; i <= NF; i++)
+ printf("%s:", $i)
+ printf("\n")
+ }
+}'
diff --git a/source3/script/wscript_build b/source3/script/wscript_build
new file mode 100644
index 0000000..66acf1c
--- /dev/null
+++ b/source3/script/wscript_build
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+
+from samba_utils import MODE_755
+
+bld.INSTALL_FILES('${BINDIR}',
+ 'smbtar',
+ chmod=MODE_755, flat=True)
+bld.INSTALL_FILES('${BINDIR}', 'samba-log-parser', chmod=MODE_755, flat=True)
+
+# Callout scripts for use in selftest environment
+bld.SAMBA_SCRIPT('smbaddshare', pattern='smbaddshare', installdir='.')
+bld.SAMBA_SCRIPT('smbchangeshare', pattern='smbchangeshare', installdir='.')
+bld.SAMBA_SCRIPT('smbdeleteshare', pattern='smbdeleteshare', installdir='.')