r4261: added the RAW_FILEINFO_EA_LIST trans2 qfileinfo and qpathinfo
authorAndrew Tridgell <tridge@samba.org>
Fri, 17 Dec 2004 22:47:49 +0000 (22:47 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:07:29 +0000 (13:07 -0500)
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.

source/include/smb_interfaces.h
source/include/trans2.h
source/libcli/raw/raweas.c
source/libcli/raw/rawfileinfo.c
source/ntvfs/posix/pvfs_qfileinfo.c
source/smb_server/trans2.c
source/torture/torture_util.c

index d5e43633db2edae5575b456a04519dee44c980a9..9916bf2385e1770ce25bbe32d2c75c38407dfc4e 100644 (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_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 
index 9d934deacef79de3848cc00319a7a75550dc9904..9afb9d4c2d88c66ca9e152c85063dc06cf382798 100644 (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
index 14d4557995d8a5a994ca571eb273d58983d4bd20..ec8bacdf6460882cffd73100bcf8bbaf85f50323 100644 (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;
+}
index 6f875f51a7717874d5ca332bf4aacf2cc709303e..8f694a23d87056aad1dc8e581f58214d43c5fc85 100644 (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;
 }
 
 /****************************************************************************
index fe53b0a415837f4f7724e861feb8fe18941f8f92..ae55ad5e98a00a477c73813b7bd61f461aaa92cb 100644 (file)
 #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);
 
index 3ca9bafcfa1d76c5e32dc3e83f75a838c908b0bd..0c827c92a1e07cf468dcdfdf45e6a9a2a16d0e6d 100644 (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)) {
index d96a285b6fb116e55cef048998bd02e631340b0a..de93d6731fea808e361aac1099ff2e860bacb734 100644 (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;
        }
 
-       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;
 }