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,
} 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
*/
#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
return total;
}
+/*
+ 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
}
+/*
+ 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;
+}
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,
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;
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;
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;
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;
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);
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;
}
/****************************************************************************
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);
}
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;
}
/****************************************************************************
#include "vfs_posix.h"
#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
*/
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;
}
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);
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);
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)) {
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)) {
{
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)) {
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;
}