root/source4/torture/raw/qfileinfo.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dos_nt_time_cmp
  2. fnum_find
  3. fname_find
  4. torture_raw_qfileinfo_internals
  5. torture_raw_qfileinfo
  6. torture_raw_qfileinfo_pipe

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    RAW_FILEINFO_* individual test suite
   4    Copyright (C) Andrew Tridgell 2003
   5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
   6    
   7    This program is free software; you can redistribute it and/or modify
   8    it under the terms of the GNU General Public License as published by
   9    the Free Software Foundation; either version 3 of the License, or
  10    (at your option) any later version.
  11    
  12    This program is distributed in the hope that it will be useful,
  13    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15    GNU General Public License for more details.
  16    
  17    You should have received a copy of the GNU General Public License
  18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19 */
  20 
  21 #include "includes.h"
  22 #include "torture/torture.h"
  23 #include "libcli/raw/libcliraw.h"
  24 #include "libcli/raw/raw_proto.h"
  25 #include "libcli/libcli.h"
  26 #include "torture/util.h"
  27 #include "librpc/rpc/dcerpc.h"
  28 #include "torture/rpc/rpc.h"
  29 #include "torture/raw/proto.h"
  30 #include "param/param.h"
  31 
  32 static struct {
  33         const char *name;
  34         enum smb_fileinfo_level level;
  35         uint_t only_paths:1;
  36         uint_t only_handles:1;
  37         uint32_t capability_mask;
  38         uint_t expected_ipc_access_denied:1;
  39         NTSTATUS expected_ipc_fnum_status;
  40         NTSTATUS fnum_status, fname_status;
  41         union smb_fileinfo fnum_finfo, fname_finfo;
  42 } levels[] = {
  43         { .name = "GETATTR",
  44           .level = RAW_FILEINFO_GETATTR,         
  45           .only_paths = 1,
  46           .only_handles = 0,
  47           .expected_ipc_access_denied = 1},
  48         {  .name ="GETATTRE",                  
  49            .level = RAW_FILEINFO_GETATTRE,         
  50            .only_paths = 0, 
  51            .only_handles = 1 },
  52         {  .name ="STANDARD",                  
  53            .level = RAW_FILEINFO_STANDARD, },
  54         {  .name ="EA_SIZE",                 
  55            .level = RAW_FILEINFO_EA_SIZE },
  56         {  .name ="ALL_EAS",                 
  57            .level = RAW_FILEINFO_ALL_EAS,
  58            .expected_ipc_fnum_status = NT_STATUS_ACCESS_DENIED,
  59         },
  60         {  .name ="IS_NAME_VALID",          
  61            .level =  RAW_FILEINFO_IS_NAME_VALID,
  62            .only_paths =  1,
  63            .only_handles =  0 },
  64         {  .name ="BASIC_INFO",            
  65            .level =  RAW_FILEINFO_BASIC_INFO },
  66         {  .name ="STANDARD_INFO",         
  67            .level =  RAW_FILEINFO_STANDARD_INFO },
  68         {  .name ="EA_INFO",               
  69            .level =  RAW_FILEINFO_EA_INFO },
  70         {  .name ="NAME_INFO",           
  71            .level =  RAW_FILEINFO_NAME_INFO },
  72         {  .name ="ALL_INFO",              
  73            .level =  RAW_FILEINFO_ALL_INFO },
  74         {  .name ="ALT_NAME_INFO",        
  75            .level =  RAW_FILEINFO_ALT_NAME_INFO,
  76            .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
  77         },
  78         {  .name ="STREAM_INFO",           
  79            .level =  RAW_FILEINFO_STREAM_INFO,
  80            .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
  81         },
  82         {  .name ="COMPRESSION_INFO",        
  83            .level =  RAW_FILEINFO_COMPRESSION_INFO,
  84            .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
  85         },
  86         {  .name ="UNIX_BASIC_INFO",         
  87            .level =  RAW_FILEINFO_UNIX_BASIC,
  88            .only_paths =  0, 
  89            .only_handles = 0, 
  90            .capability_mask = CAP_UNIX},
  91         {  .name ="UNIX_LINK_INFO",          
  92            .level =  RAW_FILEINFO_UNIX_LINK, 
  93            .only_paths = 0, 
  94            .only_handles = 0, 
  95            .capability_mask = CAP_UNIX},
  96         {  .name ="BASIC_INFORMATION",      
  97            .level =  RAW_FILEINFO_BASIC_INFORMATION },
  98         {  .name ="STANDARD_INFORMATION",   
  99            .level =  RAW_FILEINFO_STANDARD_INFORMATION },
 100         {  .name ="INTERNAL_INFORMATION",   
 101            .level =  RAW_FILEINFO_INTERNAL_INFORMATION },
 102         {  .name ="EA_INFORMATION",        
 103            .level =  RAW_FILEINFO_EA_INFORMATION },
 104         { .name = "ACCESS_INFORMATION",    
 105           .level =  RAW_FILEINFO_ACCESS_INFORMATION },
 106         { .name = "NAME_INFORMATION",      
 107           .level =  RAW_FILEINFO_NAME_INFORMATION },
 108         {  .name ="POSITION_INFORMATION",  
 109            .level =  RAW_FILEINFO_POSITION_INFORMATION },
 110         {  .name ="MODE_INFORMATION",       
 111            .level =  RAW_FILEINFO_MODE_INFORMATION },
 112         {  .name ="ALIGNMENT_INFORMATION",  
 113            .level =  RAW_FILEINFO_ALIGNMENT_INFORMATION },
 114         {  .name ="ALL_INFORMATION",       
 115            .level =  RAW_FILEINFO_ALL_INFORMATION },
 116         {  .name ="ALT_NAME_INFORMATION",  
 117            .level =  RAW_FILEINFO_ALT_NAME_INFORMATION,
 118            .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
 119         },
 120         {  .name ="STREAM_INFORMATION",    
 121            .level =  RAW_FILEINFO_STREAM_INFORMATION,
 122            .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
 123         },
 124         { .name = "COMPRESSION_INFORMATION", 
 125           .level =  RAW_FILEINFO_COMPRESSION_INFORMATION,
 126           .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
 127         },
 128         {  .name ="NETWORK_OPEN_INFORMATION",
 129            .level =  RAW_FILEINFO_NETWORK_OPEN_INFORMATION,
 130            .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
 131         },
 132         { .name = "ATTRIBUTE_TAG_INFORMATION",
 133           .level =  RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION,
 134           .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER
 135         },
 136         { NULL }
 137 };
 138 
 139 /*
 140   compare a dos time (2 second resolution) to a nt time
 141 */
 142 static int dos_nt_time_cmp(time_t t, NTTIME nt)
     /* [<][>][^][v][top][bottom][index][help] */
 143 {
 144         time_t t2 = nt_time_to_unix(nt);
 145         if (abs(t2 - t) <= 2) return 0;
 146         return t2 - t;
 147 }
 148 
 149 
 150 /*
 151   find a level in the levels[] table
 152 */
 153 static union smb_fileinfo *fnum_find(const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 154 {
 155         int i;
 156         for (i=0; levels[i].name; i++) {
 157                 if (NT_STATUS_IS_OK(levels[i].fnum_status) &&
 158                     strcmp(name, levels[i].name) == 0 && 
 159                     !levels[i].only_paths) {
 160                         return &levels[i].fnum_finfo;
 161                 }
 162         }
 163         return NULL;
 164 }
 165 
 166 /*
 167   find a level in the levels[] table
 168 */
 169 static union smb_fileinfo *fname_find(bool is_ipc, const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 170 {
 171         int i;
 172         if (is_ipc) {
 173                 return NULL;
 174         }
 175         for (i=0; levels[i].name; i++) {
 176                 if (NT_STATUS_IS_OK(levels[i].fname_status) &&
 177                     strcmp(name, levels[i].name) == 0 && 
 178                     !levels[i].only_handles) {
 179                         return &levels[i].fname_finfo;
 180                 }
 181         }
 182         return NULL;
 183 }
 184 
 185 /* local macros to make the code below more readable */
 186 #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
 187         printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
 188                #n1, #v1, (uint_t)s1->n1.out.v1, \
 189                #n2, #v2, (uint_t)s2->n2.out.v2, \
 190                __FILE__, __LINE__); \
 191         ret = false; \
 192 }} while(0)
 193 
 194 #define STR_EQUAL(n1, v1, n2, v2) do {if (strcmp_safe(s1->n1.out.v1.s, s2->n2.out.v2.s) || \
 195                                           s1->n1.out.v1.private_length != s2->n2.out.v2.private_length) { \
 196         printf("%s/%s [%s/%d] != %s/%s [%s/%d] at %s(%d)\n", \
 197                #n1, #v1, s1->n1.out.v1.s, s1->n1.out.v1.private_length, \
 198                #n2, #v2, s2->n2.out.v2.s, s2->n2.out.v2.private_length, \
 199                __FILE__, __LINE__); \
 200         ret = false; \
 201 }} while(0)
 202 
 203 #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
 204         printf("%s/%s != %s/%s at %s(%d)\n", \
 205                #n1, #v1, \
 206                #n2, #v2, \
 207                __FILE__, __LINE__); \
 208         ret = false; \
 209 }} while(0)
 210 
 211 /* used to find hints on unknown values - and to make sure 
 212    we zero-fill */
 213 #if 0 /* unused */
 214 #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
 215         printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
 216                #n1, #v1, \
 217                (uint_t)s1->n1.out.v1, \
 218                (uint_t)s1->n1.out.v1, \
 219                __FILE__, __LINE__); \
 220         ret = false; \
 221 }} while(0)
 222 #endif
 223 
 224 /* basic testing of all RAW_FILEINFO_* calls 
 225    for each call we test that it succeeds, and where possible test 
 226    for consistency between the calls. 
 227 */
 228 static bool torture_raw_qfileinfo_internals(struct torture_context *torture, 
     /* [<][>][^][v][top][bottom][index][help] */
 229                                             TALLOC_CTX *mem_ctx,        
 230                                             struct smbcli_tree *tree, 
 231                                             int fnum, const char *fname,
 232                                             bool is_ipc)
 233 {
 234         int i;
 235         bool ret = true;
 236         int count;
 237         union smb_fileinfo *s1, *s2;    
 238         NTTIME correct_time;
 239         uint64_t correct_size;
 240         uint32_t correct_attrib;
 241         const char *correct_name;
 242         bool skip_streams = false;
 243 
 244         /* scan all the fileinfo and pathinfo levels */
 245         for (i=0; levels[i].name; i++) {
 246                 if (!levels[i].only_paths) {
 247                         levels[i].fnum_finfo.generic.level = levels[i].level;
 248                         levels[i].fnum_finfo.generic.in.file.fnum = fnum;
 249                         levels[i].fnum_status = smb_raw_fileinfo(tree, mem_ctx, 
 250                                                                  &levels[i].fnum_finfo);
 251                 }
 252 
 253                 if (!levels[i].only_handles) {
 254                         levels[i].fname_finfo.generic.level = levels[i].level;
 255                         levels[i].fname_finfo.generic.in.file.path = talloc_strdup(mem_ctx, fname);
 256                         levels[i].fname_status = smb_raw_pathinfo(tree, mem_ctx, 
 257                                                                   &levels[i].fname_finfo);
 258                 }
 259         }
 260 
 261         /* check for completely broken levels */
 262         for (count=i=0; levels[i].name; i++) {
 263                 uint32_t cap = tree->session->transport->negotiate.capabilities;
 264                 /* see if this server claims to support this level */
 265                 if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
 266                         continue;
 267                 }
 268 
 269                 if (is_ipc) {
 270                         if (levels[i].expected_ipc_access_denied && NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, levels[i].fname_status)) {
 271                         } else if (!levels[i].only_handles && !NT_STATUS_EQUAL(NT_STATUS_INVALID_DEVICE_REQUEST, levels[i].fname_status)) {
 272                                 printf("ERROR: fname level %s failed, expected NT_STATUS_INVALID_DEVICE_REQUEST - %s\n", 
 273                                        levels[i].name, nt_errstr(levels[i].fname_status));
 274                                 count++;
 275                         }
 276                         if (!levels[i].only_paths && !NT_STATUS_EQUAL(levels[i].expected_ipc_fnum_status, levels[i].fnum_status)) {
 277                                 printf("ERROR: fnum level %s failed, expected %s - %s\n", 
 278                                        levels[i].name, nt_errstr(levels[i].expected_ipc_fnum_status), 
 279                                        nt_errstr(levels[i].fnum_status));
 280                                 count++;
 281                         }
 282                 } else {
 283                         if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
 284                                 printf("ERROR: fnum level %s failed - %s\n", 
 285                                        levels[i].name, nt_errstr(levels[i].fnum_status));
 286                                 count++;
 287                         }
 288                         if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
 289                                 printf("ERROR: fname level %s failed - %s\n", 
 290                                        levels[i].name, nt_errstr(levels[i].fname_status));
 291                                 count++;
 292                         }
 293                 }
 294                 
 295         }
 296 
 297         if (count != 0) {
 298                 ret = false;
 299                 printf("%d levels failed\n", count);
 300                 if (count > 35) {
 301                         torture_fail(torture, "too many level failures - giving up");
 302                 }
 303         }
 304 
 305         /* see if we can do streams */
 306         s1 = fnum_find("STREAM_INFO");
 307         if (!s1 || s1->stream_info.out.num_streams == 0) {
 308                 if (!is_ipc) {
 309                         printf("STREAM_INFO broken (%d) - skipping streams checks\n",
 310                                s1 ? s1->stream_info.out.num_streams : -1);
 311                 }
 312                 skip_streams = true;
 313         }       
 314 
 315 
 316         /* this code is incredibly repititive but doesn't lend itself to loops, so
 317            we use lots of macros to make it less painful */
 318 
 319         /* first off we check the levels that are supposed to be aliases. It will be quite rare for 
 320            this code to fail, but we need to check it for completeness */
 321 
 322 
 323 
 324 #define ALIAS_CHECK(sname1, sname2) \
 325         do { \
 326                 s1 = fnum_find(sname1);  s2 = fnum_find(sname2); \
 327                 if (s1 && s2) { INFO_CHECK } \
 328                 s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
 329                 if (s1 && s2) { INFO_CHECK } \
 330                 s1 = fnum_find(sname1);  s2 = fname_find(is_ipc, sname2); \
 331                 if (s1 && s2) { INFO_CHECK } \
 332         } while (0)
 333 
 334 #define INFO_CHECK \
 335                 STRUCT_EQUAL(basic_info,  create_time, basic_info, create_time); \
 336                 STRUCT_EQUAL(basic_info,  access_time, basic_info, access_time); \
 337                 STRUCT_EQUAL(basic_info,  write_time,  basic_info, write_time); \
 338                 STRUCT_EQUAL(basic_info,  change_time, basic_info, change_time); \
 339                 VAL_EQUAL   (basic_info,  attrib,      basic_info, attrib);
 340 
 341         ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
 342 
 343 #undef INFO_CHECK
 344 #define INFO_CHECK \
 345                 VAL_EQUAL(standard_info,  alloc_size,     standard_info, alloc_size); \
 346                 VAL_EQUAL(standard_info,  size,           standard_info, size); \
 347                 VAL_EQUAL(standard_info,  nlink,          standard_info, nlink); \
 348                 VAL_EQUAL(standard_info,  delete_pending, standard_info, delete_pending); \
 349                 VAL_EQUAL(standard_info,  directory,      standard_info, directory);
 350 
 351         ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
 352 
 353 #undef INFO_CHECK
 354 #define INFO_CHECK \
 355                 VAL_EQUAL(ea_info,  ea_size,     ea_info, ea_size);
 356 
 357         ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
 358 
 359 #undef INFO_CHECK
 360 #define INFO_CHECK \
 361                 STR_EQUAL(name_info,  fname,   name_info, fname);
 362 
 363         ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
 364 
 365 #undef INFO_CHECK
 366 #define INFO_CHECK \
 367                 STRUCT_EQUAL(all_info,  create_time,           all_info, create_time); \
 368                 STRUCT_EQUAL(all_info,  access_time,           all_info, access_time); \
 369                 STRUCT_EQUAL(all_info,  write_time,            all_info, write_time); \
 370                 STRUCT_EQUAL(all_info,  change_time,           all_info, change_time); \
 371                    VAL_EQUAL(all_info,  attrib,                all_info, attrib); \
 372                    VAL_EQUAL(all_info,  alloc_size,            all_info, alloc_size); \
 373                    VAL_EQUAL(all_info,  size,                  all_info, size); \
 374                    VAL_EQUAL(all_info,  nlink,                 all_info, nlink); \
 375                    VAL_EQUAL(all_info,  delete_pending,        all_info, delete_pending); \
 376                    VAL_EQUAL(all_info,  directory,             all_info, directory); \
 377                    VAL_EQUAL(all_info,  ea_size,               all_info, ea_size); \
 378                    STR_EQUAL(all_info,  fname,                 all_info, fname);
 379 
 380         ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
 381 
 382 #undef INFO_CHECK
 383 #define INFO_CHECK \
 384                 VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
 385                 VAL_EQUAL(compression_info, format,         compression_info, format); \
 386                 VAL_EQUAL(compression_info, unit_shift,     compression_info, unit_shift); \
 387                 VAL_EQUAL(compression_info, chunk_shift,    compression_info, chunk_shift); \
 388                 VAL_EQUAL(compression_info, cluster_shift,  compression_info, cluster_shift);
 389 
 390         ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
 391 
 392 
 393 #undef INFO_CHECK
 394 #define INFO_CHECK \
 395                 STR_EQUAL(alt_name_info,  fname,   alt_name_info, fname);
 396 
 397         ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
 398 
 399 
 400 #define TIME_CHECK_NT(sname, stype, tfield) do { \
 401         s1 = fnum_find(sname); \
 402         if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
 403                 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
 404                        nt_time_string(mem_ctx, s1->stype.out.tfield), \
 405                        nt_time_string(mem_ctx, correct_time)); \
 406                 ret = false; \
 407         } \
 408         s1 = fname_find(is_ipc, sname); \
 409         if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
 410                 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
 411                        nt_time_string(mem_ctx, s1->stype.out.tfield), \
 412                        nt_time_string(mem_ctx, correct_time)); \
 413                 ret = false; \
 414         }} while (0)
 415 
 416 #define TIME_CHECK_DOS(sname, stype, tfield) do { \
 417         s1 = fnum_find(sname); \
 418         if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
 419                 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
 420                        timestring(mem_ctx, s1->stype.out.tfield), \
 421                        nt_time_string(mem_ctx, correct_time)); \
 422                 ret = false; \
 423         } \
 424         s1 = fname_find(is_ipc, sname); \
 425         if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
 426                 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
 427                        timestring(mem_ctx, s1->stype.out.tfield), \
 428                        nt_time_string(mem_ctx, correct_time)); \
 429                 ret = false; \
 430         }} while (0)
 431 
 432 #if 0 /* unused */
 433 #define TIME_CHECK_UNX(sname, stype, tfield) do { \
 434         s1 = fnum_find(sname); \
 435         if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
 436                 printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
 437                        timestring(mem_ctx, s1->stype.out.tfield), \
 438                        nt_time_string(mem_ctx, correct_time)); \
 439                 ret = false; \
 440         } \
 441         s1 = fname_find(is_ipc, sname); \
 442         if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
 443                 printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
 444                        timestring(mem_ctx, s1->stype.out.tfield), \
 445                        nt_time_string(mem_ctx, correct_time)); \
 446                 ret = false; \
 447         }} while (0)
 448 #endif
 449 
 450         /* now check that all the times that are supposed to be equal are correct */
 451         s1 = fnum_find("BASIC_INFO");
 452         correct_time = s1->basic_info.out.create_time;
 453         torture_comment(torture, "create_time: %s\n", nt_time_string(mem_ctx, correct_time));
 454 
 455         TIME_CHECK_NT ("BASIC_INFO",               basic_info, create_time);
 456         TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, create_time);
 457         TIME_CHECK_DOS("GETATTRE",                 getattre,   create_time);
 458         TIME_CHECK_DOS("STANDARD",                 standard,   create_time);
 459         TIME_CHECK_DOS("EA_SIZE",                  ea_size,    create_time);
 460         TIME_CHECK_NT ("ALL_INFO",                 all_info,   create_time);
 461         TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
 462 
 463         s1 = fnum_find("BASIC_INFO");
 464         correct_time = s1->basic_info.out.access_time;
 465         torture_comment(torture, "access_time: %s\n", nt_time_string(mem_ctx, correct_time));
 466 
 467         TIME_CHECK_NT ("BASIC_INFO",               basic_info, access_time);
 468         TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, access_time);
 469         TIME_CHECK_DOS("GETATTRE",                 getattre,   access_time);
 470         TIME_CHECK_DOS("STANDARD",                 standard,   access_time);
 471         TIME_CHECK_DOS("EA_SIZE",                  ea_size,    access_time);
 472         TIME_CHECK_NT ("ALL_INFO",                 all_info,   access_time);
 473         TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
 474 
 475         s1 = fnum_find("BASIC_INFO");
 476         correct_time = s1->basic_info.out.write_time;
 477         torture_comment(torture, "write_time : %s\n", nt_time_string(mem_ctx, correct_time));
 478 
 479         TIME_CHECK_NT ("BASIC_INFO",               basic_info, write_time);
 480         TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, write_time);
 481         TIME_CHECK_DOS("GETATTR",                  getattr,    write_time);
 482         TIME_CHECK_DOS("GETATTRE",                 getattre,   write_time);
 483         TIME_CHECK_DOS("STANDARD",                 standard,   write_time);
 484         TIME_CHECK_DOS("EA_SIZE",                  ea_size,    write_time);
 485         TIME_CHECK_NT ("ALL_INFO",                 all_info,   write_time);
 486         TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
 487 
 488         s1 = fnum_find("BASIC_INFO");
 489         correct_time = s1->basic_info.out.change_time;
 490         torture_comment(torture, "change_time: %s\n", nt_time_string(mem_ctx, correct_time));
 491 
 492         TIME_CHECK_NT ("BASIC_INFO",               basic_info, change_time);
 493         TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, change_time);
 494         TIME_CHECK_NT ("ALL_INFO",                 all_info,   change_time);
 495         TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
 496 
 497 
 498 #define SIZE_CHECK(sname, stype, tfield) do { \
 499         s1 = fnum_find(sname); \
 500         if (s1 && s1->stype.out.tfield != correct_size) { \
 501                 printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield,  \
 502                        (uint_t)s1->stype.out.tfield, \
 503                        (uint_t)correct_size); \
 504                 ret = false; \
 505         } \
 506         s1 = fname_find(is_ipc, sname); \
 507         if (s1 && s1->stype.out.tfield != correct_size) { \
 508                 printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield,  \
 509                        (uint_t)s1->stype.out.tfield, \
 510                        (uint_t)correct_size); \
 511                 ret = false; \
 512         }} while (0)
 513 
 514         s1 = fnum_find("STANDARD_INFO");
 515         correct_size = s1->standard_info.out.size;
 516         torture_comment(torture, "size: %u\n", (uint_t)correct_size);
 517         
 518         SIZE_CHECK("GETATTR",                  getattr,                  size);
 519         SIZE_CHECK("GETATTRE",                 getattre,                 size);
 520         SIZE_CHECK("STANDARD",                 standard,                 size);
 521         SIZE_CHECK("EA_SIZE",                  ea_size,                  size);
 522         SIZE_CHECK("STANDARD_INFO",            standard_info,            size);
 523         SIZE_CHECK("STANDARD_INFORMATION",     standard_info,            size);
 524         SIZE_CHECK("ALL_INFO",                 all_info,                 size);
 525         SIZE_CHECK("ALL_INFORMATION",          all_info,                 size);
 526         SIZE_CHECK("COMPRESSION_INFO",         compression_info,         compressed_size);
 527         SIZE_CHECK("COMPRESSION_INFORMATION",  compression_info,         compressed_size);
 528         SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
 529         if (!skip_streams) {
 530                 SIZE_CHECK("STREAM_INFO",              stream_info,   streams[0].size);
 531                 SIZE_CHECK("STREAM_INFORMATION",       stream_info,   streams[0].size);
 532         }
 533 
 534 
 535         s1 = fnum_find("STANDARD_INFO");
 536         correct_size = s1->standard_info.out.alloc_size;
 537         torture_comment(torture, "alloc_size: %u\n", (uint_t)correct_size);
 538         
 539         SIZE_CHECK("GETATTRE",                 getattre,                 alloc_size);
 540         SIZE_CHECK("STANDARD",                 standard,                 alloc_size);
 541         SIZE_CHECK("EA_SIZE",                  ea_size,                  alloc_size);
 542         SIZE_CHECK("STANDARD_INFO",            standard_info,            alloc_size);
 543         SIZE_CHECK("STANDARD_INFORMATION",     standard_info,            alloc_size);
 544         SIZE_CHECK("ALL_INFO",                 all_info,                 alloc_size);
 545         SIZE_CHECK("ALL_INFORMATION",          all_info,                 alloc_size);
 546         SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
 547         if (!skip_streams) {
 548                 SIZE_CHECK("STREAM_INFO",              stream_info,   streams[0].alloc_size);
 549                 SIZE_CHECK("STREAM_INFORMATION",       stream_info,   streams[0].alloc_size);
 550         }
 551 
 552 #define ATTRIB_CHECK(sname, stype, tfield) do { \
 553         s1 = fnum_find(sname); \
 554         if (s1 && s1->stype.out.tfield != correct_attrib) { \
 555                 printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield,  \
 556                        (uint_t)s1->stype.out.tfield, \
 557                        (uint_t)correct_attrib); \
 558                 ret = false; \
 559         } \
 560         s1 = fname_find(is_ipc, sname); \
 561         if (s1 && s1->stype.out.tfield != correct_attrib) { \
 562                 printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield,  \
 563                        (uint_t)s1->stype.out.tfield, \
 564                        (uint_t)correct_attrib); \
 565                 ret = false; \
 566         }} while (0)
 567 
 568         s1 = fnum_find("BASIC_INFO");
 569         correct_attrib = s1->basic_info.out.attrib;
 570         torture_comment(torture, "attrib: 0x%x\n", (uint_t)correct_attrib);
 571         
 572         ATTRIB_CHECK("GETATTR",                   getattr,                   attrib);
 573         if (!is_ipc) {
 574                 ATTRIB_CHECK("GETATTRE",                  getattre,                  attrib);
 575                 ATTRIB_CHECK("STANDARD",                  standard,                  attrib);
 576                 ATTRIB_CHECK("EA_SIZE",                   ea_size,                   attrib);
 577         }
 578         ATTRIB_CHECK("BASIC_INFO",                basic_info,                attrib);
 579         ATTRIB_CHECK("BASIC_INFORMATION",         basic_info,                attrib);
 580         ATTRIB_CHECK("ALL_INFO",                  all_info,                  attrib);
 581         ATTRIB_CHECK("ALL_INFORMATION",           all_info,                  attrib);
 582         ATTRIB_CHECK("NETWORK_OPEN_INFORMATION",  network_open_information,  attrib);
 583         ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
 584 
 585         correct_name = fname;
 586         torture_comment(torture, "name: %s\n", correct_name);
 587 
 588 #define NAME_CHECK(sname, stype, tfield, flags) do { \
 589         s1 = fnum_find(sname); \
 590         if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
 591                         wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
 592                 printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield,  \
 593                        s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
 594                 ret = false; \
 595         } \
 596         s1 = fname_find(is_ipc, sname); \
 597         if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
 598                         wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
 599                 printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield,  \
 600                        s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
 601                 ret = false; \
 602         }} while (0)
 603 
 604         NAME_CHECK("NAME_INFO",        name_info, fname, STR_UNICODE);
 605         NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
 606 
 607         /* the ALL_INFO file name is the full path on the filesystem */
 608         s1 = fnum_find("ALL_INFO");
 609         if (s1 && !s1->all_info.out.fname.s) {
 610                 torture_fail(torture, "ALL_INFO didn't give a filename");
 611         }
 612         if (s1 && s1->all_info.out.fname.s) {
 613                 char *p = strrchr(s1->all_info.out.fname.s, '\\');
 614                 if (!p) {
 615                         printf("Not a full path in all_info/fname? - '%s'\n", 
 616                                s1->all_info.out.fname.s);
 617                         ret = false;
 618                 } else {
 619                         if (strcmp_safe(correct_name, p) != 0) {
 620                                 printf("incorrect basename in all_info/fname - '%s'\n",
 621                                        s1->all_info.out.fname.s);
 622                                 ret = false;
 623                         }
 624                 }
 625                 if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, tree->session->transport)) {
 626                         printf("Should not null terminate all_info/fname\n");
 627                         ret = false;
 628                 }
 629         }
 630 
 631         s1 = fnum_find("ALT_NAME_INFO");
 632         if (s1) {
 633                 correct_name = s1->alt_name_info.out.fname.s;
 634                 torture_comment(torture, "alt_name: %s\n", correct_name);
 635                 
 636                 NAME_CHECK("ALT_NAME_INFO",        alt_name_info, fname, STR_UNICODE);
 637                 NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
 638                 
 639                 /* and make sure we can open by alternate name */
 640                 smbcli_close(tree, fnum);
 641                 fnum = smbcli_nt_create_full(tree, correct_name, 0, 
 642                                              SEC_RIGHTS_FILE_ALL,
 643                                              FILE_ATTRIBUTE_NORMAL,
 644                                              NTCREATEX_SHARE_ACCESS_DELETE|
 645                                              NTCREATEX_SHARE_ACCESS_READ|
 646                                              NTCREATEX_SHARE_ACCESS_WRITE, 
 647                                              NTCREATEX_DISP_OVERWRITE_IF, 
 648                                              0, 0);
 649                 if (fnum == -1) {
 650                         printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree));
 651                         ret = false;
 652                 }
 653                 
 654                 if (!skip_streams) {
 655                         correct_name = "::$DATA";
 656                         torture_comment(torture, "stream_name: %s\n", correct_name);
 657                         
 658                         NAME_CHECK("STREAM_INFO",        stream_info, streams[0].stream_name, STR_UNICODE);
 659                         NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
 660                 }
 661         }
 662                 
 663         /* make sure the EAs look right */
 664         s1 = fnum_find("ALL_EAS");
 665         s2 = fnum_find("ALL_INFO");
 666         if (s1) {
 667                 for (i=0;i<s1->all_eas.out.num_eas;i++) {
 668                         printf("  flags=%d %s=%*.*s\n", 
 669                                s1->all_eas.out.eas[i].flags,
 670                                s1->all_eas.out.eas[i].name.s,
 671                                (int)s1->all_eas.out.eas[i].value.length,
 672                                (int)s1->all_eas.out.eas[i].value.length,
 673                                s1->all_eas.out.eas[i].value.data);
 674                 }
 675         }
 676         if (s1 && s2) {
 677                 if (s1->all_eas.out.num_eas == 0) {
 678                         if (s2->all_info.out.ea_size != 0) {
 679                                 printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
 680                                        s2->all_info.out.ea_size);
 681                         }
 682                 } else {
 683                         if (s2->all_info.out.ea_size != 
 684                             ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
 685                                 printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
 686                                        (int)ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
 687                                        (int)s2->all_info.out.ea_size);
 688                         }
 689                 }
 690         }
 691         s2 = fname_find(is_ipc, "ALL_EAS");
 692         if (s2) {
 693                 VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
 694                 for (i=0;i<s1->all_eas.out.num_eas;i++) {
 695                         VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
 696                         STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
 697                         VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
 698                 }
 699         }
 700 
 701 #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
 702         s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
 703         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
 704                 printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
 705                        #stype1, #tfield1, #stype2, #tfield2,  \
 706                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
 707                 ret = false; \
 708         } \
 709         s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
 710         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
 711                 printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
 712                        #stype1, #tfield1, #stype2, #tfield2,  \
 713                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
 714                 ret = false; \
 715         } \
 716         s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
 717         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
 718                 printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
 719                        #stype1, #tfield1, #stype2, #tfield2,  \
 720                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
 721                 ret = false; \
 722         } \
 723         s1 = fname_find(is_ipc, sname1); s2 = fnum_find(sname2); \
 724         if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
 725                 printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
 726                        #stype1, #tfield1, #stype2, #tfield2,  \
 727                        s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
 728                 ret = false; \
 729         }} while (0)
 730 
 731         VAL_CHECK("STANDARD_INFO", standard_info, delete_pending, 
 732                   "ALL_INFO",      all_info,      delete_pending);
 733         VAL_CHECK("STANDARD_INFO", standard_info, directory, 
 734                   "ALL_INFO",      all_info,      directory);
 735         VAL_CHECK("STANDARD_INFO", standard_info, nlink, 
 736                   "ALL_INFO",      all_info,      nlink);
 737         s1 = fnum_find("BASIC_INFO");
 738         if (s1 && is_ipc) {
 739                 if (s1->basic_info.out.attrib != FILE_ATTRIBUTE_NORMAL) {
 740                         printf("(%d) attrib basic_info/nlink incorrect - %d should be %d\n", __LINE__, s1->basic_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
 741                         ret = false;
 742                 }
 743         }
 744         s1 = fnum_find("STANDARD_INFO");
 745         if (s1 && is_ipc) {
 746                 if (s1->standard_info.out.nlink != 1) {
 747                         printf("(%d) nlinks standard_info/nlink incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.nlink);
 748                         ret = false;
 749                 }
 750                 if (s1->standard_info.out.delete_pending != 1) {
 751                         printf("(%d) nlinks standard_info/delete_pending incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.delete_pending);
 752                         ret = false;
 753                 }
 754         }
 755         VAL_CHECK("EA_INFO",       ea_info,       ea_size, 
 756                   "ALL_INFO",      all_info,      ea_size);
 757         if (!is_ipc) {
 758                 VAL_CHECK("EA_SIZE",       ea_size,       ea_size, 
 759                           "ALL_INFO",      all_info,      ea_size);
 760         }
 761 
 762 #define NAME_PATH_CHECK(sname, stype, field) do { \
 763         s1 = fname_find(is_ipc, sname); s2 = fnum_find(sname); \
 764         if (s1 && s2) { \
 765                 VAL_EQUAL(stype, field, stype, field); \
 766         } \
 767 } while (0)
 768 
 769 
 770         s1 = fnum_find("INTERNAL_INFORMATION");
 771         if (s1) {
 772                 torture_comment(torture, "file_id=%.0f\n", (double)s1->internal_information.out.file_id);
 773         }
 774 
 775         NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
 776         NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
 777         if (s1 && s2) {
 778                 printf("fnum pos = %.0f, fname pos = %.0f\n",
 779                        (double)s2->position_information.out.position,
 780                        (double)s1->position_information.out.position );
 781         }
 782         NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
 783         NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
 784         NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
 785         NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
 786 
 787 #if 0
 788         /* these are expected to differ */
 789         NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
 790 #endif
 791 
 792 #if 0 /* unused */
 793 #define UNKNOWN_CHECK(sname, stype, tfield) do { \
 794         s1 = fnum_find(sname); \
 795         if (s1 && s1->stype.out.tfield != 0) { \
 796                 printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
 797                        #stype, #tfield, \
 798                        (uint_t)s1->stype.out.tfield); \
 799         } \
 800         s1 = fname_find(is_ipc, sname); \
 801         if (s1 && s1->stype.out.tfield != 0) { \
 802                 printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
 803                        #stype, #tfield, \
 804                        (uint_t)s1->stype.out.tfield); \
 805         }} while (0)
 806 #endif
 807         /* now get a bit fancier .... */
 808         
 809         /* when we set the delete disposition then the link count should drop
 810            to 0 and delete_pending should be 1 */
 811         
 812         return ret;
 813 }
 814 
 815 /* basic testing of all RAW_FILEINFO_* calls 
 816    for each call we test that it succeeds, and where possible test 
 817    for consistency between the calls. 
 818 */
 819 bool torture_raw_qfileinfo(struct torture_context *torture, 
     /* [<][>][^][v][top][bottom][index][help] */
 820                                                    struct smbcli_state *cli)
 821 {
 822         int fnum;
 823         bool ret;
 824         const char *fname = "\\torture_qfileinfo.txt";
 825 
 826         fnum = create_complex_file(cli, torture, fname);
 827         if (fnum == -1) {
 828                 printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
 829                 return false;
 830         }
 831 
 832         ret = torture_raw_qfileinfo_internals(torture, torture, cli->tree, fnum, fname, false /* is_ipc */);
 833         
 834         smbcli_close(cli->tree, fnum);
 835         smbcli_unlink(cli->tree, fname);
 836 
 837         return ret;
 838 }
 839 
 840 bool torture_raw_qfileinfo_pipe(struct torture_context *torture, 
     /* [<][>][^][v][top][bottom][index][help] */
 841                                 struct smbcli_state *cli)
 842 {
 843         bool ret = true;
 844         int fnum;
 845         const char *fname = "\\lsass";
 846         struct dcerpc_pipe *p;
 847         struct smbcli_tree *ipc_tree;
 848         NTSTATUS status;
 849 
 850         if (!(p = dcerpc_pipe_init(torture, cli->tree->session->transport->socket->event.ctx,
 851                                    lp_iconv_convenience(torture->lp_ctx)))) {
 852                 return false;
 853         }
 854 
 855         status = dcerpc_pipe_open_smb(p, cli->tree, fname);
 856         torture_assert_ntstatus_ok(torture, status, "dcerpc_pipe_open_smb failed");
 857 
 858         ipc_tree = dcerpc_smb_tree(p->conn);
 859         fnum = dcerpc_smb_fnum(p->conn);
 860 
 861         ret = torture_raw_qfileinfo_internals(torture, torture, ipc_tree, fnum, fname, true /* is_ipc */);
 862         
 863         talloc_free(p);
 864         return ret;
 865 }

/* [<][>][^][v][top][bottom][index][help] */