root/source4/torture/raw/eas.c

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

DEFINITIONS

This source file includes following definitions.
  1. check_ea
  2. test_eas
  3. test_one_eamax
  4. test_max_eas
  5. test_nttrans_create
  6. torture_raw_eas
  7. torture_max_eas

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

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