##################################################################
#
# Check the finer aspects of create
#
# Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
#
##################################################################

##################################################################
#
# Initialization
#
##################################################################
INIT {
	global	ARGS host path

	if {[llength $ARGS] < 1} {
		set host "localhost"
	} else {
		set host [lindex $ARGS 0]
	}
	if {[llength $ARGS] < 2} {
		set path "/tmp/nfsbench"
	} else {
		set path [lindex $ARGS 1]
	}

	set mnt [rpc create $host mount 1]
	set nfs [rpc create $host nfs 2]
	set root [$mnt mount $path]
}

##################################################################
# Helper function for various create() tests
##################################################################
proc create_test {sattr} {

	global nfs root

	catch {$nfs remove $root test}
	return [$nfs create $root test $sattr]
}

proc create_test_root {sattr} {

	set uid [rpc setuid 0]
	set gid [rpc setgid 0]
	set failed [catch {set result [create_test $sattr]} error]
	rpc setuid $uid
	rpc setgid $gid
	if {$failed} {
		return -code error $error
	}
	return $result
}

##################################################################
#
# Check for uid masking bug
#
##################################################################
TEST	uid0001		Check for uid masking bug
BODY {
	set uid [expr 1 << 31]
	if [catch {set result [create_test "-uid $uid"]}] {
		# everything fine, server rejected attack
	} else {
		set ruid [lindex $result 4]
		if {$ruid == 0} {
			ERROR "server created file with uid 0"
		} elseif {$ruid != $uid} {
			WARN "server silently mapped uid $uid to $ruid"
		}
	}
}

##################################################################
TEST	cre0001		Check whether create accepts default mode
FAIL {	WARN "server doesn't accept default file permissions in create call" }
BODY {
	create_test {}
}

##################################################################
TEST	cre0002		Check for mode 0xffff bug compatibility
FAIL {	WARN "server doesn't handle sattr mode client bug" }
BODY {
	create_test {-mode 0xffff}
}

##################################################################
TEST	cre0003		Check for DIR type in create
BODY {
	if [catch {set result [create_test {-mode 04077}]}] {
		# everything fine
	} elseif {[lindex $result 1] != "REG"} {
		WARN "server doesn't ignore file type bits in sattr mode"
	}
}

##################################################################
TEST	rootsqh		Check for root squashing
BODY {
	set result [create_test_root {-mode 0666}]
	set no_root_squash [expr [lindex $result 4] == 0]
	if {!$no_root_squash} {
		NOTICE "remote server has root squashing enabled,\
			skipping some tests"
	}
}

##################################################################
TEST	cre0004		Check for CHR type in create
FAIL {	WARN "server doesn't handle create of character devices" }
COND	no_root_squash
BODY {
	set result [create_test_root {-mode 020600 -size 0x0103}]
}

##################################################################
TEST	cre0005		Check for BLK type in create
FAIL {	WARN "server doesn't handle create of block devices" }
COND	no_root_squash
BODY {
	set result [create_test_root {-mode 060600 -size 0x0103}]
}

##################################################################
TEST	cre0006		Check for SOCK type in create
FAIL {	WARN "server doesn't handle create of UNIX sockets" }
BODY {
	set result [create_test {-mode 0140600}]
	set ftype [lindex $result 1];
	if {$ftype != "SOCK"} {
		WARN "server returns file type $ftype for UNIX socket"
	}
}

##################################################################
TEST	cre0007		Check for FIFO type in create
FAIL {	WARN "server doesn't handle create of FIFOs" }
BODY {
	set result [create_test {-mode 020600 -size 0xffff}]
	set ftype [lindex $result 1];
	if {$ftype != "FIFO"} {
		WARN "server returns file type $ftype for named pipe"
	}
}

##################################################################
TEST	cre0008		Cleanup after create tests
BODY {
	catch {$nfs remove $root test}
}

##################################################################
#
# Check for setgid directories and Ultrix (or was it IRIX?) bug
# Some clients set the gid attribute to the directory's gid when
# creating a file in a setgid directory
#
##################################################################
TEST	cresgid		Check for setgid directories
BODY {
	set gid [rpc setgid 6666]
	set fh [$nfs mkdir $root "testdir" {-mode 02777}]
	rpc setgid $gid
}

##################################################################
TEST	cre0009		Check for create in setgid directories
COND	cresgid
BODY {
	set result [$nfs create $fh "test" {-mode 0666}]
	set rgid [lindex $result 5]
	if {$rgid == 6666} {
		NOTICE "server supports setgid directories"
	}
}

##################################################################
TEST	cre0010		Check whether server handles client setgid bug
COND	cresgid
FAIL {	WARN "server doesn't handle client setgid dir bug correctly" }
BODY {
	set result [$nfs create $fh "test" {-mode 0666 -gid 6666}]
}

##################################################################
TEST	cre0010		Cleanup after setgid dir test
BODY {
	catch {$nfs remove $fh "test"}
	catch {$nfs rmdir $root "testdir"}
}

##################################################################
#
# Check whether the server recognizes bad file names in create calls
#
##################################################################
TEST	cre0020		Check for foo/bar handling in create
BODY {
	catch {$nfs remove $root "testdir/test"}
	catch {$nfs rmdir $root "testdir"}
	set fh [lindex [$nfs mkdir $root "testdir" {-mode 0777}] 0]
	if {![catch {$nfs create $root "testdir/test" {-mode 0666}} error]} {
		ERROR "server doesn't reject slashes in create call"
	}
	if {![catch {$nfs lookup $fh "test"}]} {
		ERROR "server returns error \"$error\" but creates file"
	} elseif {![catch {$nfs lookup $root "testdir/test"}]} {
		ERROR "server creates directory entry \"testdir/test\"!";
	}
}

##################################################################
TEST	cre0021		Cleanup after cre0020 test
BODY {
	catch {$nfs remove $root "testdir/test"}
	catch {$nfs rmdir $root "testdir"}
}
