1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-02 09:47:23 +03:00

r4261: added the RAW_FILEINFO_EA_LIST trans2 qfileinfo and qpathinfo

level. Interestingly, this level did now show up on our trans2 scanner
previously as we didn't have the FLAGS2_EXTENDED_ATTRIBUTES bit set in
the client code. Now that we set that bit, new levels appear in
windows servers.
(This used to be commit 0b76d405a73e924dc2706f28bbf1084a59c9b393)
This commit is contained in:
Andrew Tridgell 2004-12-17 22:47:49 +00:00 committed by Gerald (Jerry) Carter
parent daae3bbb29
commit b706555b3a
7 changed files with 313 additions and 53 deletions

View File

@ -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_EA_LIST interface */
struct {
enum smb_fileinfo_level level;
union smb_fileinfo_in file;
struct {
uint_t num_names;
struct ea_name {
WIRE_STRING name;
} *ea_names;
} in;
struct smb_ea_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 {
/* the ea_size is implied by the list */
uint_t num_eas;
struct ea_struct *eas;
} out;
struct smb_ea_list out;
} all_eas;
/* trans2 qpathinfo RAW_FILEINFO_IS_NAME_VALID interface

View File

@ -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

View File

@ -36,6 +36,19 @@ uint_t ea_list_size(uint_t num_eas, struct ea_struct *eas)
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
@ -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;
}

View File

@ -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;
}
/****************************************************************************

View File

@ -24,6 +24,45 @@
#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
*/
@ -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);

View File

@ -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)) {

View File

@ -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;
}
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 (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;
}
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);
if (value != NULL) {
printf("attr '%s' not found\n", eaname);
return NT_STATUS_NONEXISTENT_EA_ENTRY;
}
return NT_STATUS_OK;
return NT_STATUS_EA_CORRUPT_ERROR;
}