summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/include/smb_interfaces.h21
-rw-r--r--source4/include/trans2.h1
-rw-r--r--source4/libcli/raw/raweas.c116
-rw-r--r--source4/libcli/raw/rawfileinfo.c64
-rw-r--r--source4/ntvfs/posix/pvfs_qfileinfo.c58
-rw-r--r--source4/smb_server/trans2.c27
-rw-r--r--source4/torture/torture_util.c73
7 files changed, 310 insertions, 50 deletions
diff --git a/source4/include/smb_interfaces.h b/source4/include/smb_interfaces.h
index d5e43633db..9916bf2385 100644
--- a/source4/include/smb_interfaces.h
+++ b/source4/include/smb_interfaces.h
@@ -313,6 +313,7 @@ enum smb_fileinfo_level {
RAW_FILEINFO_SEC_DESC, /* NT_TRANSACT_QUERY_SECURITY_DESC */
RAW_FILEINFO_STANDARD = SMB_QFILEINFO_STANDARD,
RAW_FILEINFO_EA_SIZE = SMB_QFILEINFO_EA_SIZE,
+ RAW_FILEINFO_EA_LIST = SMB_QFILEINFO_EA_LIST,
RAW_FILEINFO_ALL_EAS = SMB_QFILEINFO_ALL_EAS,
RAW_FILEINFO_IS_NAME_VALID = SMB_QFILEINFO_IS_NAME_VALID,
RAW_FILEINFO_BASIC_INFO = SMB_QFILEINFO_BASIC_INFO,
@@ -443,16 +444,30 @@ union smb_fileinfo {
} out;
} ea_size;
- /* trans2 RAW_FILEINFO_ALL_EAS interface */
+ /* trans2 RAW_FILEINFO_EA_LIST interface */
struct {
enum smb_fileinfo_level level;
- union smb_fileinfo_in in;
+ union smb_fileinfo_in file;
+
+ struct {
+ uint_t num_names;
+ struct ea_name {
+ WIRE_STRING name;
+ } *ea_names;
+ } in;
struct smb_ea_list {
- /* the ea_size is implied by the list */
uint_t num_eas;
struct ea_struct *eas;
} out;
+ } ea_list;
+
+ /* trans2 RAW_FILEINFO_ALL_EAS interface */
+ struct {
+ enum smb_fileinfo_level level;
+ union smb_fileinfo_in in;
+
+ struct smb_ea_list out;
} all_eas;
/* trans2 qpathinfo RAW_FILEINFO_IS_NAME_VALID interface
diff --git a/source4/include/trans2.h b/source4/include/trans2.h
index 9d934deace..9afb9d4c2d 100644
--- a/source4/include/trans2.h
+++ b/source4/include/trans2.h
@@ -126,6 +126,7 @@ Found 8 aliased levels
*/
#define SMB_QFILEINFO_STANDARD 1
#define SMB_QFILEINFO_EA_SIZE 2
+#define SMB_QFILEINFO_EA_LIST 3
#define SMB_QFILEINFO_ALL_EAS 4
#define SMB_QFILEINFO_IS_NAME_VALID 6 /* only for QPATHINFO */
#define SMB_QFILEINFO_BASIC_INFO 0x101
diff --git a/source4/libcli/raw/raweas.c b/source4/libcli/raw/raweas.c
index 14d4557995..ec8bacdf64 100644
--- a/source4/libcli/raw/raweas.c
+++ b/source4/libcli/raw/raweas.c
@@ -37,6 +37,19 @@ uint_t ea_list_size(uint_t num_eas, struct ea_struct *eas)
}
/*
+ work out how many bytes on the wire a ea name list will consume.
+*/
+static uint_t ea_name_list_size(uint_t num_names, struct ea_name *eas)
+{
+ uint_t total = 4;
+ int i;
+ for (i=0;i<num_names;i++) {
+ total += 1 + strlen(eas[i].name.s) + 1;
+ }
+ return total;
+}
+
+/*
work out how many bytes on the wire a chained ea list will consume.
This assumes the names are strict ascii, which should be a
reasonable assumption
@@ -242,4 +255,107 @@ NTSTATUS ea_pull_list_chained(const DATA_BLOB *blob,
}
+/*
+ pull a ea_name from a buffer. Return the number of bytes consumed
+*/
+static uint_t ea_pull_name(const DATA_BLOB *blob,
+ TALLOC_CTX *mem_ctx,
+ struct ea_name *ea)
+{
+ uint8_t nlen;
+
+ if (blob->length < 2) {
+ return 0;
+ }
+
+ nlen = CVAL(blob->data, 0);
+
+ if (nlen+2 > blob->length) {
+ return 0;
+ }
+
+ ea->name.s = talloc_strndup(mem_ctx, (const char *)(blob->data+1), nlen);
+ ea->name.private_length = nlen;
+
+ return nlen+2;
+}
+
+
+/*
+ pull a ea_name list from a buffer
+*/
+NTSTATUS ea_pull_name_list(const DATA_BLOB *blob,
+ TALLOC_CTX *mem_ctx,
+ uint_t *num_names, struct ea_name **ea_names)
+{
+ int n;
+ uint32_t ea_size, ofs;
+
+ if (blob->length < 4) {
+ return NT_STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ ea_size = IVAL(blob->data, 0);
+ if (ea_size > blob->length) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ofs = 4;
+ n = 0;
+ *num_names = 0;
+ *ea_names = NULL;
+
+ while (ofs < ea_size) {
+ uint_t len;
+ DATA_BLOB blob2;
+
+ blob2.data = blob->data + ofs;
+ blob2.length = ea_size - ofs;
+
+ *ea_names = talloc_realloc_p(mem_ctx, *ea_names, struct ea_name, n+1);
+ if (! *ea_names) return NT_STATUS_NO_MEMORY;
+
+ len = ea_pull_name(&blob2, mem_ctx, &(*ea_names)[n]);
+ if (len == 0) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ofs += len;
+ n++;
+ }
+
+ *num_names = n;
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ put a ea_name list into a data blob
+*/
+BOOL ea_push_name_list(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *data, uint_t num_names, struct ea_name *eas)
+{
+ int i;
+ uint32_t ea_size;
+ uint32_t off;
+
+ ea_size = ea_name_list_size(num_names, eas);
+
+ *data = data_blob_talloc(mem_ctx, NULL, ea_size);
+ if (data->data == NULL) {
+ return False;
+ }
+
+ SIVAL(data->data, 0, ea_size);
+ off = 4;
+ for (i=0;i<num_names;i++) {
+ uint_t nlen = strlen(eas[i].name.s);
+ SCVAL(data->data, off, nlen);
+ memcpy(data->data+off+1, eas[i].name.s, nlen+1);
+ off += 1+nlen+1;
+ }
+
+ return True;
+}
diff --git a/source4/libcli/raw/rawfileinfo.c b/source4/libcli/raw/rawfileinfo.c
index 6f875f51a7..8f694a23d8 100644
--- a/source4/libcli/raw/rawfileinfo.c
+++ b/source4/libcli/raw/rawfileinfo.c
@@ -79,6 +79,12 @@ static NTSTATUS smb_raw_info_backend(struct smbcli_session *session,
parms->ea_size.out.ea_size = IVAL(blob->data, 22);
return NT_STATUS_OK;
+ case RAW_FILEINFO_EA_LIST:
+ FINFO_CHECK_MIN_SIZE(4);
+ return ea_pull_list(blob, mem_ctx,
+ &parms->ea_list.out.num_eas,
+ &parms->ea_list.out.eas);
+
case RAW_FILEINFO_ALL_EAS:
FINFO_CHECK_MIN_SIZE(4);
return ea_pull_list(blob, mem_ctx,
@@ -280,7 +286,9 @@ static NTSTATUS smb_raw_info_backend(struct smbcli_session *session,
Very raw query file info - returns param/data blobs - (async send)
****************************************************************************/
static struct smbcli_request *smb_raw_fileinfo_blob_send(struct smbcli_tree *tree,
- uint16_t fnum, uint16_t info_level)
+ uint16_t fnum,
+ uint16_t info_level,
+ DATA_BLOB data)
{
struct smb_trans2 tp;
uint16_t setup = TRANSACT2_QFILEINFO;
@@ -291,7 +299,7 @@ static struct smbcli_request *smb_raw_fileinfo_blob_send(struct smbcli_tree *tre
tp.in.flags = 0;
tp.in.timeout = 0;
tp.in.setup_count = 1;
- tp.in.data = data_blob(NULL, 0);
+ tp.in.data = data;
tp.in.max_param = 2;
tp.in.max_data = smb_raw_max_trans_data(tree, 2);
tp.in.setup = &setup;
@@ -332,8 +340,9 @@ static NTSTATUS smb_raw_fileinfo_blob_recv(struct smbcli_request *req,
Very raw query path info - returns param/data blobs (async send)
****************************************************************************/
static struct smbcli_request *smb_raw_pathinfo_blob_send(struct smbcli_tree *tree,
- const char *fname,
- uint16_t info_level)
+ const char *fname,
+ uint16_t info_level,
+ DATA_BLOB data)
{
struct smb_trans2 tp;
uint16_t setup = TRANSACT2_QPATHINFO;
@@ -344,7 +353,7 @@ static struct smbcli_request *smb_raw_pathinfo_blob_send(struct smbcli_tree *tre
tp.in.flags = 0;
tp.in.timeout = 0;
tp.in.setup_count = 1;
- tp.in.data = data_blob(NULL, 0);
+ tp.in.data = data;
tp.in.max_param = 2;
tp.in.max_data = smb_raw_max_trans_data(tree, 2);
tp.in.setup = &setup;
@@ -463,6 +472,9 @@ failed:
struct smbcli_request *smb_raw_fileinfo_send(struct smbcli_tree *tree,
union smb_fileinfo *parms)
{
+ DATA_BLOB data;
+ struct smbcli_request *req;
+
/* pass off the non-trans2 level to specialised functions */
if (parms->generic.level == RAW_FILEINFO_GETATTRE) {
return smb_raw_getattrE_send(tree, parms);
@@ -474,9 +486,24 @@ struct smbcli_request *smb_raw_fileinfo_send(struct smbcli_tree *tree,
return NULL;
}
- return smb_raw_fileinfo_blob_send(tree,
- parms->generic.in.fnum,
- parms->generic.level);
+ data = data_blob(NULL, 0);
+
+ if (parms->generic.level == RAW_FILEINFO_EA_LIST) {
+ if (!ea_push_name_list(tree,
+ &data,
+ parms->ea_list.in.num_names,
+ parms->ea_list.in.ea_names)) {
+ return NULL;
+ }
+ }
+
+ req = smb_raw_fileinfo_blob_send(tree,
+ parms->generic.in.fnum,
+ parms->generic.level, data);
+
+ data_blob_free(&data);
+
+ return req;
}
/****************************************************************************
@@ -525,6 +552,9 @@ NTSTATUS smb_raw_fileinfo(struct smbcli_tree *tree,
struct smbcli_request *smb_raw_pathinfo_send(struct smbcli_tree *tree,
union smb_fileinfo *parms)
{
+ DATA_BLOB data;
+ struct smbcli_request *req;
+
if (parms->generic.level == RAW_FILEINFO_GETATTR) {
return smb_raw_getattr_send(tree, parms);
}
@@ -532,8 +562,22 @@ struct smbcli_request *smb_raw_pathinfo_send(struct smbcli_tree *tree,
return NULL;
}
- return smb_raw_pathinfo_blob_send(tree, parms->generic.in.fname,
- parms->generic.level);
+ data = data_blob(NULL, 0);
+
+ if (parms->generic.level == RAW_FILEINFO_EA_LIST) {
+ if (!ea_push_name_list(tree,
+ &data,
+ parms->ea_list.in.num_names,
+ parms->ea_list.in.ea_names)) {
+ return NULL;
+ }
+ }
+
+ req = smb_raw_pathinfo_blob_send(tree, parms->generic.in.fname,
+ parms->generic.level, data);
+ data_blob_free(&data);
+
+ return req;
}
/****************************************************************************
diff --git a/source4/ntvfs/posix/pvfs_qfileinfo.c b/source4/ntvfs/posix/pvfs_qfileinfo.c
index fe53b0a415..ae55ad5e98 100644
--- a/source4/ntvfs/posix/pvfs_qfileinfo.c
+++ b/source4/ntvfs/posix/pvfs_qfileinfo.c
@@ -25,6 +25,45 @@
#include "librpc/gen_ndr/ndr_xattr.h"
/*
+ reply to a RAW_FILEINFO_EA_LIST call
+*/
+static NTSTATUS pvfs_query_ea_list(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
+ struct pvfs_filename *name, int fd,
+ uint_t num_names,
+ struct ea_name *names,
+ struct smb_ea_list *eas)
+{
+ NTSTATUS status;
+ int i;
+ struct xattr_DosEAs *ealist = talloc_p(mem_ctx, struct xattr_DosEAs);
+
+ ZERO_STRUCTP(eas);
+ status = pvfs_doseas_load(pvfs, name, fd, ealist);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ eas->eas = talloc_array_p(mem_ctx, struct ea_struct, num_names);
+ if (eas->eas == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ eas->num_eas = num_names;
+ for (i=0;i<num_names;i++) {
+ int j;
+ eas->eas[i].flags = 0;
+ eas->eas[i].name.s = names[i].name.s;
+ eas->eas[i].value = data_blob(NULL, 0);
+ for (j=0;j<ealist->num_eas;j++) {
+ if (StrCaseCmp(eas->eas[i].name.s,
+ ealist->eas[j].name) == 0) {
+ eas->eas[i].value = ealist->eas[j].value;
+ break;
+ }
+ }
+ }
+ return NT_STATUS_OK;
+}
+
+/*
reply to a RAW_FILEINFO_ALL_EAS call
*/
static NTSTATUS pvfs_query_all_eas(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
@@ -40,15 +79,16 @@ static NTSTATUS pvfs_query_all_eas(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- eas->num_eas = ealist->num_eas;
- eas->eas = talloc_array_p(mem_ctx, struct ea_struct, eas->num_eas);
+ eas->eas = talloc_array_p(mem_ctx, struct ea_struct, ealist->num_eas);
if (eas->eas == NULL) {
return NT_STATUS_NO_MEMORY;
}
- for (i=0;i<eas->num_eas;i++) {
- eas->eas[i].flags = 0;
- eas->eas[i].name.s = ealist->eas[i].name;
- eas->eas[i].value = ealist->eas[i].value;
+ eas->num_eas = 0;
+ for (i=0;i<ealist->num_eas;i++) {
+ eas->eas[eas->num_eas].flags = 0;
+ eas->eas[eas->num_eas].name.s = ealist->eas[i].name;
+ eas->eas[eas->num_eas].value = ealist->eas[i].value;
+ eas->num_eas++;
}
return NT_STATUS_OK;
}
@@ -91,6 +131,12 @@ static NTSTATUS pvfs_map_fileinfo(struct pvfs_state *pvfs,
info->ea_size.out.ea_size = name->dos.ea_size;
return NT_STATUS_OK;
+ case RAW_FILEINFO_EA_LIST:
+ return pvfs_query_ea_list(pvfs, req, name, fd,
+ info->ea_list.in.num_names,
+ info->ea_list.in.ea_names,
+ &info->ea_list.out);
+
case RAW_FILEINFO_ALL_EAS:
return pvfs_query_all_eas(pvfs, req, name, fd, &info->all_eas.out);
diff --git a/source4/smb_server/trans2.c b/source4/smb_server/trans2.c
index 3ca9bafcfa..0c827c92a1 100644
--- a/source4/smb_server/trans2.c
+++ b/source4/smb_server/trans2.c
@@ -614,6 +614,15 @@ static NTSTATUS trans2_fileinfo_fill(struct smbsrv_request *req, struct smb_tran
st->alignment_information.out.alignment_requirement);
return NT_STATUS_OK;
+ case RAW_FILEINFO_EA_LIST:
+ list_size = ea_list_size(st->ea_list.out.num_eas,
+ st->ea_list.out.eas);
+ trans2_setup_reply(req, trans, 2, list_size, 0);
+ SSVAL(trans->out.params.data, 0, 0);
+ ea_put_list(trans->out.data.data,
+ st->ea_list.out.num_eas, st->ea_list.out.eas);
+ return NT_STATUS_OK;
+
case RAW_FILEINFO_ALL_EAS:
list_size = ea_list_size(st->all_eas.out.num_eas,
st->all_eas.out.eas);
@@ -753,6 +762,15 @@ static NTSTATUS trans2_qpathinfo(struct smbsrv_request *req, struct smb_trans2 *
return NT_STATUS_INVALID_LEVEL;
}
+ if (st.generic.level == RAW_FILEINFO_EA_LIST) {
+ status = ea_pull_name_list(&trans->in.data, req,
+ &st.ea_list.in.num_names,
+ &st.ea_list.in.ea_names);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
/* call the backend */
status = ntvfs_qpathinfo(req, &st);
if (!NT_STATUS_IS_OK(status)) {
@@ -789,6 +807,15 @@ static NTSTATUS trans2_qfileinfo(struct smbsrv_request *req, struct smb_trans2 *
return NT_STATUS_INVALID_LEVEL;
}
+ if (st.generic.level == RAW_FILEINFO_EA_LIST) {
+ status = ea_pull_name_list(&trans->in.data, req,
+ &st.ea_list.in.num_names,
+ &st.ea_list.in.ea_names);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
/* call the backend */
status = ntvfs_qfileinfo(req, &st);
if (!NT_STATUS_IS_OK(status)) {
diff --git a/source4/torture/torture_util.c b/source4/torture/torture_util.c
index d96a285b6f..de93d6731f 100644
--- a/source4/torture/torture_util.c
+++ b/source4/torture/torture_util.c
@@ -362,11 +362,15 @@ NTSTATUS torture_check_ea(struct smbcli_state *cli,
{
union smb_fileinfo info;
NTSTATUS status;
- int i;
+ struct ea_name ea;
TALLOC_CTX *mem_ctx = talloc(cli, 0);
- info.all_eas.level = RAW_FILEINFO_ALL_EAS;
- info.all_eas.in.fname = fname;
+ info.ea_list.level = RAW_FILEINFO_EA_LIST;
+ info.ea_list.file.fname = fname;
+ info.ea_list.in.num_names = 1;
+ info.ea_list.in.ea_names = &ea;
+
+ ea.name.s = eaname;
status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
if (!NT_STATUS_IS_OK(status)) {
@@ -374,38 +378,45 @@ NTSTATUS torture_check_ea(struct smbcli_state *cli,
return status;
}
- for (i=0;i<info.all_eas.out.num_eas;i++) {
- if (StrCaseCmp(eaname, info.all_eas.out.eas[i].name.s) == 0) {
- if (value == NULL) {
- printf("attr '%s' should not be present\n", eaname);
- talloc_free(mem_ctx);
- return NT_STATUS_EA_CORRUPT_ERROR;
- }
- if (strlen(value) == info.all_eas.out.eas[i].value.length &&
- memcmp(value,
- info.all_eas.out.eas[i].value.data,
- info.all_eas.out.eas[i].value.length) == 0) {
- talloc_free(mem_ctx);
- return NT_STATUS_OK;
- } else {
- printf("attr '%s' has wrong value '%*.*s'\n",
- eaname,
- info.all_eas.out.eas[i].value.length,
- info.all_eas.out.eas[i].value.length,
- info.all_eas.out.eas[i].value.data);
- talloc_free(mem_ctx);
- return NT_STATUS_EA_CORRUPT_ERROR;
- }
- }
+ if (info.ea_list.out.num_eas != 1) {
+ printf("Expected 1 ea in ea_list\n");
+ talloc_free(mem_ctx);
+ return NT_STATUS_EA_CORRUPT_ERROR;
}
- talloc_free(mem_ctx);
+ if (StrCaseCmp(eaname, info.ea_list.out.eas[0].name.s) != 0) {
+ printf("Expected ea '%s' not '%s' in ea_list\n",
+ eaname, info.ea_list.out.eas[0].name.s);
+ talloc_free(mem_ctx);
+ return NT_STATUS_EA_CORRUPT_ERROR;
+ }
+
+ if (value == NULL) {
+ if (info.ea_list.out.eas[0].value.length != 0) {
+ printf("Expected zero length ea for %s\n", eaname);
+ talloc_free(mem_ctx);
+ return NT_STATUS_EA_CORRUPT_ERROR;
+ }
+ talloc_free(mem_ctx);
+ return NT_STATUS_OK;
+ }
- if (value != NULL) {
- printf("attr '%s' not found\n", eaname);
- return NT_STATUS_NONEXISTENT_EA_ENTRY;
+ if (strlen(value) == info.ea_list.out.eas[0].value.length &&
+ memcmp(value, info.ea_list.out.eas[0].value.data,
+ info.ea_list.out.eas[0].value.length) == 0) {
+ talloc_free(mem_ctx);
+ return NT_STATUS_OK;
}
- return NT_STATUS_OK;
+ printf("Expected value '%s' not '%*.*s' for ea %s\n",
+ value,
+ info.ea_list.out.eas[0].value.length,
+ info.ea_list.out.eas[0].value.length,
+ info.ea_list.out.eas[0].value.data,
+ eaname);
+
+ talloc_free(mem_ctx);
+
+ return NT_STATUS_EA_CORRUPT_ERROR;
}