r12608: Remove some unused #include lines.
[kamenim/samba.git] / source4 / torture / raw / eas.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    test DOS extended attributes
5
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Guenter Kukkukk 2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "libcli/raw/libcliraw.h"
26
27 #define BASEDIR "\\testeas"
28
29 #define CHECK_STATUS(status, correct) do { \
30         if (!NT_STATUS_EQUAL(status, correct)) { \
31                 printf("(%s) Incorrect status %s - should be %s\n", \
32                        __location__, nt_errstr(status), nt_errstr(correct)); \
33                 ret = False; \
34                 goto done; \
35         }} while (0)
36
37 static  BOOL maxeadebug; /* need that here, to allow no file delete in debug case */
38
39 static BOOL check_ea(struct smbcli_state *cli, 
40                      const char *fname, const char *eaname, const char *value)
41 {
42         NTSTATUS status = torture_check_ea(cli, fname, eaname, value);
43         return NT_STATUS_IS_OK(status);
44 }
45
46 static BOOL test_eas(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
47 {
48         NTSTATUS status;
49         union smb_setfileinfo setfile;
50         union smb_open io;
51         const char *fname = BASEDIR "\\ea.txt";
52         BOOL ret = True;
53         int fnum = -1;
54
55         printf("TESTING SETFILEINFO EA_SET\n");
56
57         io.generic.level = RAW_OPEN_NTCREATEX;
58         io.ntcreatex.in.root_fid = 0;
59         io.ntcreatex.in.flags = 0;
60         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
61         io.ntcreatex.in.create_options = 0;
62         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
63         io.ntcreatex.in.share_access = 
64                 NTCREATEX_SHARE_ACCESS_READ | 
65                 NTCREATEX_SHARE_ACCESS_WRITE;
66         io.ntcreatex.in.alloc_size = 0;
67         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
68         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
69         io.ntcreatex.in.security_flags = 0;
70         io.ntcreatex.in.fname = fname;
71         status = smb_raw_open(cli->tree, mem_ctx, &io);
72         CHECK_STATUS(status, NT_STATUS_OK);
73         fnum = io.ntcreatex.out.fnum;
74         
75         ret &= check_ea(cli, fname, "EAONE", NULL);
76
77         printf("Adding first two EAs\n");
78         setfile.generic.level = RAW_SFILEINFO_EA_SET;
79         setfile.generic.file.fnum = fnum;
80         setfile.ea_set.in.num_eas = 2;
81         setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
82         setfile.ea_set.in.eas[0].flags = 0;
83         setfile.ea_set.in.eas[0].name.s = "EAONE";
84         setfile.ea_set.in.eas[0].value = data_blob_string_const("VALUE1");
85         setfile.ea_set.in.eas[1].flags = 0;
86         setfile.ea_set.in.eas[1].name.s = "SECONDEA";
87         setfile.ea_set.in.eas[1].value = data_blob_string_const("ValueTwo");
88
89         status = smb_raw_setfileinfo(cli->tree, &setfile);
90         CHECK_STATUS(status, NT_STATUS_OK);
91
92         ret &= check_ea(cli, fname, "EAONE", "VALUE1");
93         ret &= check_ea(cli, fname, "SECONDEA", "ValueTwo");
94
95         printf("Modifying 2nd EA\n");
96         setfile.ea_set.in.num_eas = 1;
97         setfile.ea_set.in.eas[0].name.s = "SECONDEA";
98         setfile.ea_set.in.eas[0].value = data_blob_string_const(" Changed Value");
99         status = smb_raw_setfileinfo(cli->tree, &setfile);
100         CHECK_STATUS(status, NT_STATUS_OK);
101
102         ret &= check_ea(cli, fname, "EAONE", "VALUE1");
103         ret &= check_ea(cli, fname, "SECONDEA", " Changed Value");
104
105         printf("Setting a NULL EA\n");
106         setfile.ea_set.in.eas[0].value = data_blob(NULL, 0);
107         setfile.ea_set.in.eas[0].name.s = "NULLEA";
108         status = smb_raw_setfileinfo(cli->tree, &setfile);
109         CHECK_STATUS(status, NT_STATUS_OK);
110
111         ret &= check_ea(cli, fname, "EAONE", "VALUE1");
112         ret &= check_ea(cli, fname, "SECONDEA", " Changed Value");
113         ret &= check_ea(cli, fname, "NULLEA", NULL);
114
115         printf("Deleting first EA\n");
116         setfile.ea_set.in.eas[0].flags = 0;
117         setfile.ea_set.in.eas[0].name.s = "EAONE";
118         setfile.ea_set.in.eas[0].value = data_blob(NULL, 0);
119         status = smb_raw_setfileinfo(cli->tree, &setfile);
120         CHECK_STATUS(status, NT_STATUS_OK);
121
122         ret &= check_ea(cli, fname, "EAONE", NULL);
123         ret &= check_ea(cli, fname, "SECONDEA", " Changed Value");
124
125         printf("Deleting second EA\n");
126         setfile.ea_set.in.eas[0].flags = 0;
127         setfile.ea_set.in.eas[0].name.s = "SECONDEA";
128         setfile.ea_set.in.eas[0].value = data_blob(NULL, 0);
129         status = smb_raw_setfileinfo(cli->tree, &setfile);
130         CHECK_STATUS(status, NT_STATUS_OK);
131
132         ret &= check_ea(cli, fname, "EAONE", NULL);
133         ret &= check_ea(cli, fname, "SECONDEA", NULL);
134
135 done:
136         smbcli_close(cli->tree, fnum);
137         return ret;
138 }
139
140
141 /*
142  * Helper function to retrieve the max. ea size for one ea name
143  */
144 static int test_one_eamax(struct smbcli_state *cli, const int fnum, 
145                           const char *eaname, DATA_BLOB eablob, 
146                           const int eastart, const int eadebug) 
147 {
148         NTSTATUS status;
149         struct ea_struct eastruct;
150         union smb_setfileinfo setfile;
151         int i, high, low, maxeasize;
152
153         setfile.generic.level = RAW_SFILEINFO_EA_SET;
154         setfile.generic.file.fnum = fnum;
155         setfile.ea_set.in.num_eas = 1;
156         setfile.ea_set.in.eas = &eastruct;
157         setfile.ea_set.in.eas->flags = 0;
158         setfile.ea_set.in.eas->name.s = eaname;
159         setfile.ea_set.in.eas->value = eablob;
160
161         maxeasize = eablob.length;
162         i = eastart;
163         low = 0;
164         high = maxeasize;
165
166         do {
167                 if (eadebug) {
168                         printf ("Testing EA size: %d\n", i);
169                 }
170                 setfile.ea_set.in.eas->value.length = i;
171
172                 status = smb_raw_setfileinfo(cli->tree, &setfile);
173
174                 if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
175                         if (eadebug) {
176                                 printf ("[%s] EA size %d succeeded! "
177                                         "(high=%d low=%d)\n", 
178                                         eaname, i, high, low);
179                         }
180                         low = i;
181                         if (low == maxeasize) {
182                                 printf ("Max. EA size for \"%s\"=%d "
183                                         "[but could be possibly larger]\n", 
184                                         eaname, low);
185                                 break;
186                         }
187                         if (high - low == 1 && high != maxeasize) {
188                                 printf ("Max. EA size for \"%s\"=%d\n", 
189                                         eaname, low);
190                                 break;
191                         }
192                         i += (high - low + 1) / 2;
193                 } else {
194                         if (eadebug) {
195                                 printf ("[%s] EA size %d failed!    "
196                                         "(high=%d low=%d) [%s]\n", 
197                                         eaname, i, high, low, 
198                                         nt_errstr(status));
199                         }
200                         high = i;
201                         if (high - low <= 1) {
202                                 printf ("Max. EA size for \"%s\"=%d\n", 
203                                         eaname, low);
204                                 break;
205                         }
206                         i -= (high - low + 1) / 2;
207                 }
208         } while (True);
209
210         return low;
211 }
212
213 /*
214  * Test for maximum ea size - more than one ea name is checked.
215  *
216  * Additional parameters can be passed, to allow further testing:
217  *
218  *             default
219  * maxeasize    65536   limit the max. size for a single EA name
220  * maxeanames     101   limit of the number of tested names
221  * maxeastart       1   this EA size is used to test for the 1st EA (atm)
222  * maxeadebug       0   if set True, further debug output is done - in addition
223  *                      the testfile is not deleted for further inspection!
224  *
225  * Set some/all of these options on the cmdline with:
226  * --option torture:maxeasize=1024 --option torture:maxeadebug=1 ...
227  *
228  */
229 static BOOL test_max_eas(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
230 {
231         NTSTATUS status;
232         union smb_open io;
233         const char *fname = BASEDIR "\\ea_max.txt";
234         int fnum = -1;
235         BOOL ret = True;
236         BOOL err = False;
237
238         int       i, j, k, last, total;
239         DATA_BLOB eablob;
240         char      *eaname = NULL;
241         int       maxeasize;
242         int       maxeanames;
243         int       maxeastart;
244
245         printf("TESTING SETFILEINFO MAX. EA_SET\n");
246
247         maxeasize  = lp_parm_int(-1, "torture", "maxeasize", 65536);
248         maxeanames = lp_parm_int(-1, "torture", "maxeanames", 101);
249         maxeastart = lp_parm_int(-1, "torture", "maxeastart", 1);
250         maxeadebug = lp_parm_int(-1, "torture", "maxeadebug", 0);
251
252         /* Do some sanity check on possibly passed parms */
253         if (maxeasize <= 0) {
254                 printf("Invalid parameter 'maxeasize=%d'",maxeasize);
255                 err = True;
256         }
257         if (maxeanames <= 0) {
258                 printf("Invalid parameter 'maxeanames=%d'",maxeanames);
259                 err = True;
260         }
261         if (maxeastart <= 0) {
262                 printf("Invalid parameter 'maxeastart=%d'",maxeastart);
263                 err = True;
264         }
265         if (maxeadebug < 0) {
266                 printf("Invalid parameter 'maxeadebug=%d'",maxeadebug);
267                 err = True;
268         }
269         if (err) {
270           printf("\n\n");
271           goto done;
272         }
273         if (maxeastart > maxeasize) {
274                 maxeastart = maxeasize;
275                 printf ("'maxeastart' outside range - corrected to %d\n", 
276                         maxeastart);
277         }
278         printf("MAXEA parms: maxeasize=%d maxeanames=%d maxeastart=%d"
279                " maxeadebug=%d\n", maxeasize, maxeanames, maxeastart, 
280                maxeadebug);
281
282         io.generic.level = RAW_OPEN_NTCREATEX;
283         io.ntcreatex.in.root_fid = 0;
284         io.ntcreatex.in.flags = 0;
285         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
286         io.ntcreatex.in.create_options = 0;
287         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
288         io.ntcreatex.in.share_access = 
289                 NTCREATEX_SHARE_ACCESS_READ | 
290                 NTCREATEX_SHARE_ACCESS_WRITE;
291         io.ntcreatex.in.alloc_size = 0;
292         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
293         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
294         io.ntcreatex.in.security_flags = 0;
295         io.ntcreatex.in.fname = fname;
296         status = smb_raw_open(cli->tree, mem_ctx, &io);
297         CHECK_STATUS(status, NT_STATUS_OK);
298         fnum = io.ntcreatex.out.fnum;
299         
300         eablob = data_blob_talloc(mem_ctx, NULL, maxeasize);
301         if (eablob.data == NULL) {
302                 goto done;
303         }
304         /* 
305          * Fill in some EA data - the offset could be easily checked 
306          * during a hexdump.
307          */
308         for (i = 0, k = 0; i < eablob.length / 4; i++, k+=4) {
309                 eablob.data[k]   = k & 0xff;
310                 eablob.data[k+1] = (k >>  8) & 0xff;
311                 eablob.data[k+2] = (k >> 16) & 0xff;
312                 eablob.data[k+3] = (k >> 24) & 0xff;
313         }
314
315         i = eablob.length % 4;
316         if (i-- > 0) { 
317                 eablob.data[k] = k & 0xff;
318                 if (i-- > 0) { 
319                         eablob.data[k+1] = (k >>  8) & 0xff;
320                         if (i-- > 0) { 
321                                 eablob.data[k+2] = (k >> 16) & 0xff;
322                         }
323                 }
324         }
325         /*
326          * Filesystems might allow max. EAs data for different EA names.
327          * So more than one EA name should be checked.
328          */
329         total = 0;
330         last  = maxeastart;
331
332         for (i = 0; i < maxeanames; i++) {
333                 if (eaname != NULL) {
334                         talloc_free(eaname);
335                 }
336                 eaname = talloc_asprintf(mem_ctx, "MAX%d", i);
337                 if(eaname == NULL) {
338                         goto done;
339                 }
340                 j = test_one_eamax(cli, fnum, eaname, eablob, last, maxeadebug);
341                 if (j <= 0) {
342                         break;
343                 }
344                 total += j;
345                 last = j;
346         }
347
348         printf("Total EA size:%d\n", total);
349         if (i == maxeanames) {
350                 printf ("NOTE: More EAs could be available!\n");
351         } 
352         if (total == 0) {
353                 ret = False;
354         }
355 done:
356         smbcli_close(cli->tree, fnum);
357         return ret;
358 }
359
360 /*
361   test using NTTRANS CREATE to create a file with an initial EA set
362 */
363 static BOOL test_nttrans_create(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
364 {
365         NTSTATUS status;
366         union smb_open io;
367         const char *fname = BASEDIR "\\ea2.txt";
368         BOOL ret = True;
369         int fnum = -1;
370         struct ea_struct eas[3];
371         struct smb_ea_list ea_list;
372
373         printf("TESTING NTTRANS CREATE WITH EAS\n");
374
375         io.generic.level = RAW_OPEN_NTTRANS_CREATE;
376         io.ntcreatex.in.root_fid = 0;
377         io.ntcreatex.in.flags = 0;
378         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
379         io.ntcreatex.in.create_options = 0;
380         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
381         io.ntcreatex.in.share_access = 
382                 NTCREATEX_SHARE_ACCESS_READ | 
383                 NTCREATEX_SHARE_ACCESS_WRITE;
384         io.ntcreatex.in.alloc_size = 0;
385         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
386         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
387         io.ntcreatex.in.security_flags = 0;
388         io.ntcreatex.in.fname = fname;
389
390         ea_list.num_eas = 3;
391         ea_list.eas = eas;
392
393         eas[0].flags = 0;
394         eas[0].name.s = "1st EA";
395         eas[0].value = data_blob_string_const("Value One");
396
397         eas[1].flags = 0;
398         eas[1].name.s = "2nd EA";
399         eas[1].value = data_blob_string_const("Second Value");
400
401         eas[2].flags = 0;
402         eas[2].name.s = "and 3rd";
403         eas[2].value = data_blob_string_const("final value");
404
405         io.ntcreatex.in.ea_list = &ea_list;
406         io.ntcreatex.in.sec_desc = NULL;
407
408         status = smb_raw_open(cli->tree, mem_ctx, &io);
409         CHECK_STATUS(status, NT_STATUS_OK);
410         fnum = io.ntcreatex.out.fnum;
411         
412         ret &= check_ea(cli, fname, "EAONE", NULL);
413         ret &= check_ea(cli, fname, "1st EA", "Value One");
414         ret &= check_ea(cli, fname, "2nd EA", "Second Value");
415         ret &= check_ea(cli, fname, "and 3rd", "final value");
416
417         smbcli_close(cli->tree, fnum);
418
419         printf("Trying to add EAs on non-create\n");
420         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
421         io.ntcreatex.in.fname = fname;
422
423         ea_list.num_eas = 1;
424         eas[0].flags = 0;
425         eas[0].name.s = "Fourth EA";
426         eas[0].value = data_blob_string_const("Value Four");
427
428         status = smb_raw_open(cli->tree, mem_ctx, &io);
429         CHECK_STATUS(status, NT_STATUS_OK);
430         fnum = io.ntcreatex.out.fnum;
431         
432         ret &= check_ea(cli, fname, "1st EA", "Value One");
433         ret &= check_ea(cli, fname, "2nd EA", "Second Value");
434         ret &= check_ea(cli, fname, "and 3rd", "final value");
435         ret &= check_ea(cli, fname, "Fourth EA", NULL);
436
437 done:
438         smbcli_close(cli->tree, fnum);
439         return ret;
440 }
441
442 /* 
443    basic testing of EA calls
444 */
445 BOOL torture_raw_eas(void)
446 {
447         struct smbcli_state *cli;
448         BOOL ret = True;
449         TALLOC_CTX *mem_ctx;
450
451         if (!torture_open_connection(&cli)) {
452                 return False;
453         }
454
455         mem_ctx = talloc_init("torture_raw_eas");
456
457         if (!torture_setup_dir(cli, BASEDIR)) {
458                 return False;
459         }
460
461         ret &= test_eas(cli, mem_ctx);
462         ret &= test_nttrans_create(cli, mem_ctx);
463
464         smb_raw_exit(cli->session);
465
466         torture_close_connection(cli);
467         talloc_free(mem_ctx);
468         return ret;
469 }
470
471 /* 
472    test max EA size
473 */
474 BOOL torture_max_eas(void)
475 {
476         struct smbcli_state *cli;
477         BOOL ret = True;
478         TALLOC_CTX *mem_ctx;
479
480         if (!torture_open_connection(&cli)) {
481                 return False;
482         }
483
484         mem_ctx = talloc_init("torture_raw_eas");
485
486         if (!torture_setup_dir(cli, BASEDIR)) {
487                 return False;
488         }
489
490         ret &= test_max_eas(cli, mem_ctx);
491
492         smb_raw_exit(cli->session);
493         if (!maxeadebug) {
494                 /* in no ea debug case, all files are gone now */
495                 smbcli_deltree(cli->tree, BASEDIR);
496         }
497
498         torture_close_connection(cli);
499         talloc_free(mem_ctx);
500         return ret;
501 }