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