summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/client/client.c4
-rw-r--r--source3/include/proto.h20
-rw-r--r--source3/libsmb/clifile.c451
-rw-r--r--source3/torture/torture.c73
4 files changed, 391 insertions, 157 deletions
diff --git a/source3/client/client.c b/source3/client/client.c
index 13dee6081d..d7c554efc0 100644
--- a/source3/client/client.c
+++ b/source3/client/client.c
@@ -2725,7 +2725,7 @@ static int cmd_link(void)
return 1;
}
- if (!cli_unix_hardlink(targetcli, targetname, newname)) {
+ if (!NT_STATUS_IS_OK(cli_posix_hardlink(targetcli, targetname, newname))) {
d_printf("%s linking files (%s -> %s)\n", cli_errstr(targetcli), newname, oldname);
return 1;
}
@@ -2776,7 +2776,7 @@ static int cmd_symlink(void)
return 1;
}
- if (!cli_unix_symlink(targetcli, targetname, newname)) {
+ if (!NT_STATUS_IS_OK(cli_posix_symlink(targetcli, targetname, newname))) {
d_printf("%s symlinking files (%s -> %s)\n",
cli_errstr(targetcli), newname, targetname);
return 1;
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 717a972505..a918c29aaa 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -2332,12 +2332,28 @@ void cli_reset_error(struct cli_state *cli);
/* The following definitions come from libsmb/clifile.c */
+struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *oldname,
+ const char *newname);
+NTSTATUS cli_posix_symlink_recv(struct tevent_req *req);
+NTSTATUS cli_posix_symlink(struct cli_state *cli,
+ const char *oldname,
+ const char *newname);
+struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *oldname,
+ const char *newname);
+NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req);
+NTSTATUS cli_posix_hardlink(struct cli_state *cli,
+ const char *oldname,
+ const char *newname);
uint32_t unix_perms_to_wire(mode_t perms);
mode_t wire_perms_to_unix(uint32_t perms);
bool cli_unix_getfacl(struct cli_state *cli, const char *name, size_t *prb_size, char **retbuf);
bool cli_unix_stat(struct cli_state *cli, const char *name, SMB_STRUCT_STAT *sbuf);
-bool cli_unix_symlink(struct cli_state *cli, const char *oldname, const char *newname);
-bool cli_unix_hardlink(struct cli_state *cli, const char *oldname, const char *newname);
bool cli_unix_chmod(struct cli_state *cli, const char *fname, mode_t mode);
bool cli_unix_chown(struct cli_state *cli, const char *fname, uid_t uid, gid_t gid);
struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
index 1225aa6bae..e48656b698 100644
--- a/source3/libsmb/clifile.c
+++ b/source3/libsmb/clifile.c
@@ -20,74 +20,328 @@
#include "includes.h"
+/***********************************************************
+ Common function for pushing stings, used by smb_bytes_push_str()
+ and trans_bytes_push_str(). Only difference is the align_odd
+ parameter setting.
+***********************************************************/
+
+static uint8_t *internal_bytes_push_str(uint8_t *buf, bool ucs2,
+ const char *str, size_t str_len,
+ bool align_odd,
+ size_t *pconverted_size)
+{
+ size_t buflen;
+ char *converted;
+ size_t converted_size;
+
+ if (buf == NULL) {
+ return NULL;
+ }
+
+ buflen = talloc_get_size(buf);
+
+ if (align_odd && ucs2 && (buflen % 2 == 0)) {
+ /*
+ * We're pushing into an SMB buffer, align odd
+ */
+ buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t, buflen + 1);
+ if (buf == NULL) {
+ return NULL;
+ }
+ buf[buflen] = '\0';
+ buflen += 1;
+ }
+
+ if (!convert_string_talloc(talloc_tos(), CH_UNIX,
+ ucs2 ? CH_UTF16LE : CH_DOS,
+ str, str_len, &converted,
+ &converted_size, true)) {
+ return NULL;
+ }
+
+ buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t,
+ buflen + converted_size);
+ if (buf == NULL) {
+ TALLOC_FREE(converted);
+ return NULL;
+ }
+
+ memcpy(buf + buflen, converted, converted_size);
+
+ TALLOC_FREE(converted);
+
+ if (pconverted_size) {
+ *pconverted_size = converted_size;
+ }
+
+ return buf;
+}
+
+/***********************************************************
+ Push a string into an SMB buffer, with odd byte alignment
+ if it's a UCS2 string.
+***********************************************************/
+
+uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2,
+ const char *str, size_t str_len,
+ size_t *pconverted_size)
+{
+ return internal_bytes_push_str(buf, ucs2, str, str_len,
+ true, pconverted_size);
+}
+
+/***********************************************************
+ Same as smb_bytes_push_str(), but without the odd byte
+ align for ucs2 (we're pushing into a param or data block).
+ static for now, although this will probably change when
+ other modules use async trans calls.
+***********************************************************/
+
+static uint8_t *trans2_bytes_push_str(uint8_t *buf, bool ucs2,
+ const char *str, size_t str_len,
+ size_t *pconverted_size)
+{
+ return internal_bytes_push_str(buf, ucs2, str, str_len,
+ false, pconverted_size);
+}
+
+
/****************************************************************************
Hard/Symlink a file (UNIX extensions).
Creates new name (sym)linked to oldname.
****************************************************************************/
-static bool cli_link_internal(struct cli_state *cli, const char *oldname, const char *newname, bool hard_link)
+struct link_state {
+ uint16_t setup;
+ uint8_t *param;
+ uint8_t *data;
+};
+
+static void cli_posix_link_internal_done(struct tevent_req *subreq)
{
- unsigned int data_len = 0;
- unsigned int param_len = 0;
- uint16_t setup = TRANSACT2_SETPATHINFO;
- char *param;
- char *data;
- char *rparam=NULL, *rdata=NULL;
- char *p;
- size_t oldlen = 2*(strlen(oldname)+1);
- size_t newlen = 2*(strlen(newname)+1);
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct link_state *state = tevent_req_data(req, struct link_state);
+ NTSTATUS status;
+
+ status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL, NULL, NULL);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ tevent_req_done(req);
+}
- param = SMB_MALLOC_ARRAY(char, 6+newlen+2);
+static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *oldname,
+ const char *newname,
+ bool hardlink)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct link_state *state = NULL;
- if (!param) {
- return false;
+ req = tevent_req_create(mem_ctx, &state, struct link_state);
+ if (req == NULL) {
+ return NULL;
}
- data = SMB_MALLOC_ARRAY(char, oldlen+2);
+ /* Setup setup word. */
+ SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
- if (!data) {
- SAFE_FREE(param);
- return false;
+ /* Setup param array. */
+ state->param = talloc_array(state, uint8_t, 6);
+ if (tevent_req_nomem(state->param, req)) {
+ return tevent_req_post(req, ev);
}
+ memset(state->param, '\0', 6);
+ SSVAL(state->param,0,hardlink ? SMB_SET_FILE_UNIX_HLINK : SMB_SET_FILE_UNIX_LINK);
- SSVAL(param,0,hard_link ? SMB_SET_FILE_UNIX_HLINK : SMB_SET_FILE_UNIX_LINK);
- SIVAL(param,2,0);
- p = &param[6];
+ state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), newname,
+ strlen(newname)+1, NULL);
- p += clistr_push(cli, p, newname, newlen, STR_TERMINATE);
- param_len = PTR_DIFF(p, param);
+ if (tevent_req_nomem(state->param, req)) {
+ return tevent_req_post(req, ev);
+ }
- p = data;
- p += clistr_push(cli, p, oldname, oldlen, STR_TERMINATE);
- data_len = PTR_DIFF(p, data);
+ /* Setup data array. */
+ state->data = talloc_array(state, uint8_t, 0);
+ if (tevent_req_nomem(state->data, req)) {
+ return tevent_req_post(req, ev);
+ }
+ state->data = trans2_bytes_push_str(state->data, cli_ucs2(cli), oldname,
+ strlen(oldname)+1, NULL);
- if (!cli_send_trans(cli, SMBtrans2,
- NULL, /* name */
- -1, 0, /* fid, flags */
- &setup, 1, 0, /* setup, length, max */
- param, param_len, 2, /* param, length, max */
- data, data_len, cli->max_xmit /* data, length, max */
- )) {
- SAFE_FREE(data);
- SAFE_FREE(param);
- return false;
+ subreq = cli_trans_send(state, /* mem ctx. */
+ ev, /* event ctx. */
+ cli, /* cli_state. */
+ SMBtrans2, /* cmd. */
+ NULL, /* pipe name. */
+ -1, /* fid. */
+ 0, /* function. */
+ 0, /* flags. */
+ &state->setup, /* setup. */
+ 1, /* num setup uint16_t words. */
+ 0, /* max returned setup. */
+ state->param, /* param. */
+ talloc_get_size(state->param), /* num param. */
+ 2, /* max returned param. */
+ state->data, /* data. */
+ talloc_get_size(state->data), /* num data. */
+ 0); /* max returned data. */
+
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
}
+ tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
+ return req;
+}
- SAFE_FREE(data);
- SAFE_FREE(param);
+/****************************************************************************
+ Symlink a file (UNIX extensions).
+****************************************************************************/
- if (!cli_receive_trans(cli, SMBtrans2,
- &rparam, &param_len,
- &rdata, &data_len)) {
- return false;
+struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *oldname,
+ const char *newname)
+{
+ return cli_posix_link_internal_send(mem_ctx, ev, cli,
+ oldname, newname, false);
+}
+
+NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
}
+ return NT_STATUS_OK;
+}
- SAFE_FREE(data);
- SAFE_FREE(param);
- SAFE_FREE(rdata);
- SAFE_FREE(rparam);
+NTSTATUS cli_posix_symlink(struct cli_state *cli,
+ const char *oldname,
+ const char *newname)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev = NULL;
+ struct tevent_req *req = NULL;
+ NTSTATUS status = NT_STATUS_OK;
- return true;
+ if (cli_has_async_calls(cli)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ req = cli_posix_symlink_send(frame,
+ ev,
+ cli,
+ oldname,
+ newname);
+ if (req == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ if (!tevent_req_poll(req, ev)) {
+ status = map_nt_error_from_unix(errno);
+ goto fail;
+ }
+
+ status = cli_posix_symlink_recv(req);
+
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
+}
+
+/****************************************************************************
+ Hard link a file (UNIX extensions).
+****************************************************************************/
+
+struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *oldname,
+ const char *newname)
+{
+ return cli_posix_link_internal_send(mem_ctx, ev, cli,
+ oldname, newname, true);
+}
+
+NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS cli_posix_hardlink(struct cli_state *cli,
+ const char *oldname,
+ const char *newname)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev = NULL;
+ struct tevent_req *req = NULL;
+ NTSTATUS status = NT_STATUS_OK;
+
+ if (cli_has_async_calls(cli)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ req = cli_posix_hardlink_send(frame,
+ ev,
+ cli,
+ oldname,
+ newname);
+ if (req == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ if (!tevent_req_poll(req, ev)) {
+ status = map_nt_error_from_unix(errno);
+ goto fail;
+ }
+
+ status = cli_posix_hardlink_recv(req);
+
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
@@ -325,25 +579,6 @@ bool cli_unix_stat(struct cli_state *cli, const char *name, SMB_STRUCT_STAT *sbu
return true;
}
-
-/****************************************************************************
- Symlink a file (UNIX extensions).
-****************************************************************************/
-
-bool cli_unix_symlink(struct cli_state *cli, const char *oldname, const char *newname)
-{
- return cli_link_internal(cli, oldname, newname, False);
-}
-
-/****************************************************************************
- Hard a file (UNIX extensions).
-****************************************************************************/
-
-bool cli_unix_hardlink(struct cli_state *cli, const char *oldname, const char *newname)
-{
- return cli_link_internal(cli, oldname, newname, True);
-}
-
/****************************************************************************
Chmod or chown a file internal (UNIX extensions).
****************************************************************************/
@@ -1288,92 +1523,6 @@ NTSTATUS cli_ntcreate(struct cli_state *cli,
return status;
}
-/***********************************************************
- Common function for pushing stings, used by smb_bytes_push_str()
- and trans_bytes_push_str(). Only difference is the align_odd
- parameter setting.
-***********************************************************/
-
-static uint8_t *internal_bytes_push_str(uint8_t *buf, bool ucs2,
- const char *str, size_t str_len,
- bool align_odd,
- size_t *pconverted_size)
-{
- size_t buflen;
- char *converted;
- size_t converted_size;
-
- if (buf == NULL) {
- return NULL;
- }
-
- buflen = talloc_get_size(buf);
-
- if (align_odd && ucs2 && (buflen % 2 == 0)) {
- /*
- * We're pushing into an SMB buffer, align odd
- */
- buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t, buflen + 1);
- if (buf == NULL) {
- return NULL;
- }
- buf[buflen] = '\0';
- buflen += 1;
- }
-
- if (!convert_string_talloc(talloc_tos(), CH_UNIX,
- ucs2 ? CH_UTF16LE : CH_DOS,
- str, str_len, &converted,
- &converted_size, true)) {
- return NULL;
- }
-
- buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t,
- buflen + converted_size);
- if (buf == NULL) {
- TALLOC_FREE(converted);
- return NULL;
- }
-
- memcpy(buf + buflen, converted, converted_size);
-
- TALLOC_FREE(converted);
-
- if (pconverted_size) {
- *pconverted_size = converted_size;
- }
-
- return buf;
-}
-
-/***********************************************************
- Push a string into an SMB buffer, with odd byte alignment
- if it's a UCS2 string.
-***********************************************************/
-
-uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2,
- const char *str, size_t str_len,
- size_t *pconverted_size)
-{
- return internal_bytes_push_str(buf, ucs2, str, str_len,
- true, pconverted_size);
-}
-
-/***********************************************************
- Same as smb_bytes_push_str(), but without the odd byte
- align for ucs2 (we're pushing into a param or data block).
- static for now, although this will probably change when
- other modules use async trans calls.
-***********************************************************/
-
-static uint8_t *trans2_bytes_push_str(uint8_t *buf, bool ucs2,
- const char *str, size_t str_len,
- size_t *pconverted_size)
-{
- return internal_bytes_push_str(buf, ucs2, str, str_len,
- false, pconverted_size);
-}
-
/****************************************************************************
Open a file
WARNING: if you open with O_WRONLY then getattrE won't work!
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 41343cab87..bff8d07f1f 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -4135,8 +4135,11 @@ static bool run_opentest(int dummy)
static bool run_simple_posix_open_test(int dummy)
{
static struct cli_state *cli1;
- const char *fname = "\\posix:file";
- const char *dname = "\\posix:dir";
+ const char *fname = "posix:file";
+ const char *hname = "posix:hlink";
+ const char *sname = "posix:symlink";
+ const char *dname = "posix:dir";
+ char buf[10];
uint16 major, minor;
uint32 caplow, caphigh;
uint16_t fnum1 = (uint16_t)-1;
@@ -4171,6 +4174,10 @@ static bool run_simple_posix_open_test(int dummy)
cli_posix_unlink(cli1, fname);
cli_setatr(cli1, dname, 0, 0);
cli_posix_rmdir(cli1, dname);
+ cli_setatr(cli1, hname, 0, 0);
+ cli_posix_unlink(cli1, hname);
+ cli_setatr(cli1, sname, 0, 0);
+ cli_posix_unlink(cli1, sname);
/* Create a directory. */
if (!NT_STATUS_IS_OK(cli_posix_mkdir(cli1, dname, 0777))) {
@@ -4222,6 +4229,64 @@ static bool run_simple_posix_open_test(int dummy)
}
}
+ /* Create the file. */
+ if (!NT_STATUS_IS_OK(cli_posix_open(cli1, fname, O_RDWR|O_CREAT|O_EXCL, 0600, &fnum1))) {
+ printf("POSIX create of %s failed (%s)\n", fname, cli_errstr(cli1));
+ goto out;
+ }
+
+ /* Write some data into it. */
+ if (cli_write(cli1, fnum1, 0, "TEST DATA\n", 0, 10) != 10) {
+ printf("cli_write failed: %s\n", cli_errstr(cli1));
+ goto out;
+ }
+
+ cli_close(cli1, fnum1);
+
+ /* Now create a hardlink. */
+ if (!NT_STATUS_IS_OK(cli_posix_hardlink(cli1, fname, hname))) {
+ printf("POSIX hardlink of %s failed (%s)\n", hname, cli_errstr(cli1));
+ goto out;
+ }
+
+ /* Now create a symlink. */
+ if (!NT_STATUS_IS_OK(cli_posix_symlink(cli1, fname, sname))) {
+ printf("POSIX symlink of %s failed (%s)\n", sname, cli_errstr(cli1));
+ goto out;
+ }
+
+ /* Open the hardlink for read. */
+ if (!NT_STATUS_IS_OK(cli_posix_open(cli1, hname, O_RDONLY, 0, &fnum1))) {
+ printf("POSIX open of %s failed (%s)\n", hname, cli_errstr(cli1));
+ goto out;
+ }
+
+ if (cli_read(cli1, fnum1, buf, 0, 10) != 10) {
+ printf("POSIX read of %s failed (%s)\n", hname, cli_errstr(cli1));
+ goto out;
+ }
+
+ if (memcmp(buf, "TEST DATA\n", 10)) {
+ printf("invalid data read from hardlink\n");
+ goto out;
+ }
+
+ cli_close(cli1, fnum1);
+
+ /* Open the symlink for read - this should fail. A POSIX
+ client should not be doing opens on a symlink. */
+ if (NT_STATUS_IS_OK(cli_posix_open(cli1, sname, O_RDONLY, 0, &fnum1))) {
+ printf("POSIX open of %s succeeded (should have failed)\n", sname);
+ goto out;
+ } else {
+ if (!check_error(__LINE__, cli1, ERRDOS, ERRbadpath,
+ NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
+ goto out;
+ }
+ }
+
+ /* TODO. Add and test cli_posix_readlink() call. */
+
if (!NT_STATUS_IS_OK(cli_posix_rmdir(cli1, dname))) {
printf("POSIX rmdir failed (%s)\n", cli_errstr(cli1));
goto out;
@@ -4237,6 +4302,10 @@ static bool run_simple_posix_open_test(int dummy)
fnum1 = (uint16_t)-1;
}
+ cli_setatr(cli1, sname, 0, 0);
+ cli_posix_unlink(cli1, sname);
+ cli_setatr(cli1, hname, 0, 0);
+ cli_posix_unlink(cli1, hname);
cli_setatr(cli1, fname, 0, 0);
cli_posix_unlink(cli1, fname);
cli_setatr(cli1, dname, 0, 0);