diff --git a/tests/client/CMakeLists.txt b/tests/client/CMakeLists.txt index 4021bcc7..70c92f13 100755 --- a/tests/client/CMakeLists.txt +++ b/tests/client/CMakeLists.txt @@ -58,6 +58,7 @@ if (WITH_SFTP) torture_sftp_expand_path torture_sftp_aio torture_sftp_home_directory + torture_sftp_setstat ${SFTP_BENCHMARK_TESTS}) endif (WITH_SFTP) diff --git a/tests/client/torture_sftp_setstat.c b/tests/client/torture_sftp_setstat.c new file mode 100644 index 00000000..f1d7b76b --- /dev/null +++ b/tests/client/torture_sftp_setstat.c @@ -0,0 +1,373 @@ +#define LIBSSH_STATIC + +#include "config.h" + +#include "libssh/sftp.h" +#include "sftp.c" +#include "torture.h" + +#include +#include +#include +#include +#include + +static int +sshd_setup(void **state) +{ + torture_setup_sshd_server(state, false); + return 0; +} + +static int +sshd_teardown(void **state) +{ + torture_teardown_sshd_server(state); + return 0; +} + +static int +session_setup_setstat(void **state) +{ + + struct torture_state *s = *state; + struct torture_sftp *t = NULL; + struct passwd *pwd = NULL; + static char name[128] = {0}; + const char *test_1 = "l&setstat_test\n"; + int rc; + + pwd = getpwnam("bob"); + assert_non_null(pwd); + + rc = setuid(pwd->pw_uid); + assert_return_code(rc, errno); + + s->ssh.session = torture_ssh_session(s, + TORTURE_SSH_SERVER, + NULL, + TORTURE_SSH_USER_ALICE, + NULL); + assert_non_null(s->ssh.session); + + s->ssh.tsftp = torture_sftp_session(s->ssh.session); + assert_non_null(s->ssh.tsftp); + + t = s->ssh.tsftp; + + snprintf(name, sizeof(name), "%s/libssh_sftp_setstat_test", t->testdir); + torture_write_file(name, test_1); + s->private_data = name; + + return 0; +} + +static int +session_setup_lsetstat(void **state) +{ + + struct torture_state *s = *state; + struct torture_sftp *t = NULL; + struct passwd *pwd = NULL; + static char path[128] = {0}; + const char *test_1 = "lsetstat_test_1\n"; + int rc; + + char tmp_file[128] = {0}; + + pwd = getpwnam("bob"); + assert_non_null(pwd); + + rc = setuid(pwd->pw_uid); + assert_return_code(rc, errno); + + s->ssh.session = torture_ssh_session(s, + TORTURE_SSH_SERVER, + NULL, + TORTURE_SSH_USER_ALICE, + NULL); + assert_non_null(s->ssh.session); + + s->ssh.tsftp = torture_sftp_session(s->ssh.session); + assert_non_null(s->ssh.tsftp); + + t = s->ssh.tsftp; + + rc = sftp_extension_supported(t->sftp, "lsetstat@openssh.com", "1"); + if (rc == 0) { + skip(); + } + + snprintf(tmp_file, sizeof(tmp_file), "%s/newfile", t->testdir); + torture_write_file(tmp_file, test_1); + + snprintf(path, sizeof(path), "%s/linkname", t->testdir); + rc = symlink(tmp_file, path); + assert_int_equal(rc, SSH_OK); + s->private_data = path; + + return 0; +} +static int +session_teardown(void **state) +{ + struct torture_state *s = *state; + + torture_rmdirs(s->ssh.tsftp->testdir); + torture_sftp_close(s->ssh.tsftp); + ssh_disconnect(s->ssh.session); + ssh_free(s->ssh.session); + + return 0; +} + +/*setstat tests*/ +static void +torture_sftp_setstat_chown(void **state) +{ + struct torture_state *s = *state; + struct torture_sftp *t = s->ssh.tsftp; + struct sftp_attributes_struct attr; + struct passwd *pwd = NULL; + sftp_attributes tmp_attr = NULL; + const char *name = (char *)s->private_data; + int rc; + + ZERO_STRUCT(attr); + + pwd = getpwnam("alice"); + assert_non_null(pwd); + + attr.uid = pwd->pw_uid; + attr.gid = pwd->pw_gid; + attr.flags = SSH_FILEXFER_ATTR_UIDGID; + + rc = sftp_setstat(t->sftp, name, &attr); + assert_int_equal(rc, SSH_OK); + tmp_attr = sftp_stat(t->sftp, name); + assert_non_null(tmp_attr); + assert_int_equal(tmp_attr->uid, pwd->pw_uid); + assert_int_equal(tmp_attr->gid, pwd->pw_gid); + sftp_attributes_free(tmp_attr); +} + +static void +torture_sftp_setstat_size(void **state) +{ + struct torture_state *s = *state; + struct torture_sftp *t = s->ssh.tsftp; + int rc; + size_t len = 30; + struct sftp_attributes_struct attr; + struct stat sb; + const char *name = (char *)s->private_data; + + ZERO_STRUCT(attr); + attr.flags = SSH_FILEXFER_ATTR_SIZE; + attr.size = len; + rc = sftp_setstat(t->sftp, name, &attr); + assert_int_equal(rc, SSH_OK); + + rc = stat(name, &sb); + assert_int_equal(rc, SSH_OK); + + assert_int_equal(len, sb.st_size); +} + +static void +torture_sftp_setstat_chmod(void **state) +{ + mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP; + struct torture_state *s = *state; + struct torture_sftp *t = s->ssh.tsftp; + int rc; + struct sftp_attributes_struct attr; + struct stat sb; + const char *name = (char *)s->private_data; + + ZERO_STRUCT(attr); + + attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS; + attr.permissions = mode; + + rc = sftp_setstat(t->sftp, name, &attr); + assert_int_equal(rc, SSH_OK); + + rc = stat(name, &sb); + assert_int_equal(rc, SSH_OK); + + assert_int_equal(sb.st_mode & ACCESSPERMS, mode); +} + +static void +torture_sftp_setstat_utimes(void **state) +{ + struct torture_state *s = *state; + struct torture_sftp *t = s->ssh.tsftp; + int rc; + struct sftp_attributes_struct attr; + struct stat sb; + int atime = 10676, mtime = 13467; + const char *name = (char *)s->private_data; + + ZERO_STRUCT(attr); + + attr.flags = SSH_FILEXFER_ATTR_ACMODTIME; + attr.mtime = mtime; + attr.atime = atime; + + rc = sftp_setstat(t->sftp, name, &attr); + assert_int_equal(rc, SSH_OK); + + rc = stat(name, &sb); + assert_int_equal(rc, SSH_OK); + assert_int_equal(sb.st_mtime, mtime); + assert_int_equal(sb.st_atime, atime); +} + +static void +torture_sftp_setstat_negative(void **state) +{ + struct torture_state *s = *state; + struct torture_sftp *t = s->ssh.tsftp; + const char *name = (char *)s->private_data; + int rc; + struct sftp_attributes_struct attr; + + ZERO_STRUCT(attr); + + attr.flags = SSH_FILEXFER_ATTR_ACMODTIME | SSH_FILEXFER_ATTR_UIDGID | + SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_SIZE; + + /* testing null sftp */ + rc = sftp_setstat(NULL, name, &attr); + assert_int_equal(rc, SSH_ERROR); + + /* testing non-existing file */ + rc = sftp_setstat(t->sftp, "not existing", &attr); + assert_int_equal(rc, SSH_ERROR); + + /* testing null attributes */ + rc = sftp_setstat(t->sftp, name, NULL); + assert_int_equal(rc, SSH_ERROR); +} + +/*lsetstat tests*/ +static void +torture_sftp_lsetstat_chown(void **state) +{ + struct torture_state *s = *state; + struct torture_sftp *t = s->ssh.tsftp; + struct passwd *pwd = NULL; + const char *name = (char *)s->private_data; + int rc; + struct sftp_attributes_struct attr; + sftp_attributes tmp_attr = NULL; + + ZERO_STRUCT(attr); + + pwd = getpwnam("alice"); + assert_non_null(pwd); + + attr.flags = SSH_FILEXFER_ATTR_UIDGID; + attr.uid = pwd->pw_uid; + attr.gid = pwd->pw_gid; + rc = sftp_lsetstat(t->sftp, name, &attr); + assert_int_equal(rc, SSH_OK); + + tmp_attr = sftp_lstat(t->sftp, name); + assert_non_null(tmp_attr); + assert_int_equal(tmp_attr->uid, pwd->pw_uid); + assert_int_equal(tmp_attr->gid, pwd->pw_gid); + sftp_attributes_free(tmp_attr); +} + +static void +torture_sftp_lsetstat_utimes(void **state) +{ + struct torture_state *s = *state; + struct torture_sftp *t = s->ssh.tsftp; + const char *name = (char *)s->private_data; + int rc; + struct sftp_attributes_struct attr; + struct stat sb; + int atime = 10676, mtime = 13467; + + ZERO_STRUCT(attr); + + attr.flags = SSH_FILEXFER_ATTR_ACMODTIME; + attr.mtime = mtime; + attr.atime = atime; + + rc = sftp_lsetstat(t->sftp, name, &attr); + assert_int_equal(rc, SSH_OK); + + rc = lstat(name, &sb); + assert_int_equal(rc, SSH_OK); + assert_int_equal(sb.st_mtime, mtime); + assert_int_equal(sb.st_atime, atime); +} + +static void +torture_sftp_lsetstat_negative(void **state) +{ + struct torture_state *s = *state; + struct torture_sftp *t = s->ssh.tsftp; + const char *name = (char *)s->private_data; + int rc; + struct sftp_attributes_struct attr; + + ZERO_STRUCT(attr); + + attr.flags = SSH_FILEXFER_ATTR_ACMODTIME | SSH_FILEXFER_ATTR_UIDGID; + + /* testing non-existing file */ + rc = sftp_lsetstat(t->sftp, "not existing", &attr); + assert_int_equal(rc, SSH_ERROR); + + /* testing null attributes */ + rc = sftp_lsetstat(t->sftp, name, NULL); + assert_int_equal(rc, SSH_ERROR); + + /* testing null sftp */ + rc = sftp_lsetstat(NULL, name, &attr); + assert_int_equal(rc, SSH_ERROR); +} + +int +torture_run_tests(void) +{ + int rc; + struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(torture_sftp_setstat_chown, + session_setup_setstat, + session_teardown), + cmocka_unit_test_setup_teardown(torture_sftp_setstat_chmod, + session_setup_setstat, + session_teardown), + cmocka_unit_test_setup_teardown(torture_sftp_setstat_utimes, + session_setup_setstat, + session_teardown), + cmocka_unit_test_setup_teardown(torture_sftp_setstat_size, + session_setup_setstat, + session_teardown), + cmocka_unit_test_setup_teardown(torture_sftp_setstat_negative, + session_setup_setstat, + session_teardown), + cmocka_unit_test_setup_teardown(torture_sftp_lsetstat_utimes, + session_setup_lsetstat, + session_teardown), + cmocka_unit_test_setup_teardown(torture_sftp_lsetstat_chown, + session_setup_lsetstat, + session_teardown), + cmocka_unit_test_setup_teardown(torture_sftp_lsetstat_negative, + session_setup_lsetstat, + session_teardown)}; + + ssh_init(); + + torture_filter_tests(tests); + rc = cmocka_run_group_tests(tests, sshd_setup, sshd_teardown); + ssh_finalize(); + return rc; +}