root/source4/torture/raw/samba3hide.c

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

DEFINITIONS

This source file includes following definitions.
  1. init_unixinfo_nochange
  2. set_visible
  3. is_visible
  4. is_readable
  5. is_writeable
  6. smbcli_file_exists
  7. smbcli_chmod
  8. torture_samba3_hide
  9. torture_samba3_closeerr

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    Test samba3 hide unreadable/unwriteable
   4    Copyright (C) Volker Lendecke 2006
   5    
   6    This program is free software; you can redistribute it and/or modify
   7    it under the terms of the GNU General Public License as published by
   8    the Free Software Foundation; either version 3 of the License, or
   9    (at your option) any later version.
  10    
  11    This program is distributed in the hope that it will be useful,
  12    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14    GNU General Public License for more details.
  15    
  16    You should have received a copy of the GNU General Public License
  17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19 
  20 #include "includes.h"
  21 #include "torture/torture.h"
  22 #include "libcli/raw/libcliraw.h"
  23 #include "system/time.h"
  24 #include "system/filesys.h"
  25 #include "libcli/libcli.h"
  26 #include "torture/util.h"
  27 
  28 static void init_unixinfo_nochange(union smb_setfileinfo *info)
     /* [<][>][^][v][top][bottom][index][help] */
  29 {
  30         ZERO_STRUCTP(info);
  31         info->unix_basic.level = RAW_SFILEINFO_UNIX_BASIC;
  32         info->unix_basic.in.mode = SMB_MODE_NO_CHANGE;
  33 
  34         info->unix_basic.in.end_of_file = SMB_SIZE_NO_CHANGE_HI;
  35         info->unix_basic.in.end_of_file <<= 32;
  36         info->unix_basic.in.end_of_file |= SMB_SIZE_NO_CHANGE_LO;
  37         
  38         info->unix_basic.in.num_bytes = SMB_SIZE_NO_CHANGE_HI;
  39         info->unix_basic.in.num_bytes <<= 32;
  40         info->unix_basic.in.num_bytes |= SMB_SIZE_NO_CHANGE_LO;
  41         
  42         info->unix_basic.in.status_change_time = SMB_TIME_NO_CHANGE_HI;
  43         info->unix_basic.in.status_change_time <<= 32;
  44         info->unix_basic.in.status_change_time |= SMB_TIME_NO_CHANGE_LO;
  45 
  46         info->unix_basic.in.access_time = SMB_TIME_NO_CHANGE_HI;
  47         info->unix_basic.in.access_time <<= 32;
  48         info->unix_basic.in.access_time |= SMB_TIME_NO_CHANGE_LO;
  49 
  50         info->unix_basic.in.change_time = SMB_TIME_NO_CHANGE_HI;
  51         info->unix_basic.in.change_time <<= 32;
  52         info->unix_basic.in.change_time |= SMB_TIME_NO_CHANGE_LO;
  53 
  54         info->unix_basic.in.uid = SMB_UID_NO_CHANGE;
  55         info->unix_basic.in.gid = SMB_GID_NO_CHANGE;
  56 }
  57 
  58 struct list_state {
  59         const char *fname;
  60         bool visible;
  61 };
  62 
  63 static void set_visible(struct clilist_file_info *i, const char *mask,
     /* [<][>][^][v][top][bottom][index][help] */
  64                         void *priv)
  65 {
  66         struct list_state *state = (struct list_state *)priv;
  67 
  68         if (strcasecmp_m(state->fname, i->name) == 0)
  69                 state->visible = true;
  70 }
  71 
  72 static bool is_visible(struct smbcli_tree *tree, const char *fname)
     /* [<][>][^][v][top][bottom][index][help] */
  73 {
  74         struct list_state state;
  75 
  76         state.visible = false;
  77         state.fname = fname;
  78 
  79         if (smbcli_list(tree, "*.*", 0, set_visible, &state) < 0) {
  80                 return false;
  81         }
  82         return state.visible;
  83 }
  84 
  85 static bool is_readable(struct smbcli_tree *tree, const char *fname)
     /* [<][>][^][v][top][bottom][index][help] */
  86 {
  87         int fnum;
  88         fnum = smbcli_open(tree, fname, O_RDONLY, DENY_NONE);
  89         if (fnum < 0) {
  90                 return false;
  91         }
  92         smbcli_close(tree, fnum);
  93         return true;
  94 }
  95 
  96 static bool is_writeable(TALLOC_CTX *mem_ctx, struct smbcli_tree *tree,
     /* [<][>][^][v][top][bottom][index][help] */
  97                          const char *fname)
  98 {
  99         int fnum;
 100         fnum = smbcli_open(tree, fname, O_WRONLY, DENY_NONE);
 101         if (fnum < 0) {
 102                 return false;
 103         }
 104         smbcli_close(tree, fnum);
 105         return true;
 106 }
 107 
 108 /*
 109  * This is not an exact method because there's a ton of reasons why a getatr
 110  * might fail. But for our purposes it's sufficient.
 111  */
 112 
 113 static bool smbcli_file_exists(struct smbcli_tree *tree, const char *fname)
     /* [<][>][^][v][top][bottom][index][help] */
 114 {
 115         return NT_STATUS_IS_OK(smbcli_getatr(tree, fname, NULL, NULL, NULL));
 116 }
 117 
 118 static NTSTATUS smbcli_chmod(struct smbcli_tree *tree, const char *fname,
     /* [<][>][^][v][top][bottom][index][help] */
 119                              uint64_t permissions)
 120 {
 121         union smb_setfileinfo sfinfo;
 122         init_unixinfo_nochange(&sfinfo);
 123         sfinfo.unix_basic.in.file.path = fname;
 124         sfinfo.unix_basic.in.permissions = permissions;
 125         return smb_raw_setpathinfo(tree, &sfinfo);
 126 }
 127 
 128 bool torture_samba3_hide(struct torture_context *torture)
     /* [<][>][^][v][top][bottom][index][help] */
 129 {
 130         struct smbcli_state *cli;
 131         const char *fname = "test.txt";
 132         int fnum;
 133         NTSTATUS status;
 134         struct smbcli_tree *hideunread;
 135         struct smbcli_tree *hideunwrite;
 136 
 137         if (!torture_open_connection_share(
 138                     torture, &cli, torture, torture_setting_string(torture, "host", NULL),
 139                     torture_setting_string(torture, "share", NULL), torture->ev)) {
 140                 d_printf("torture_open_connection_share failed\n");
 141                 return false;
 142         }
 143 
 144         status = torture_second_tcon(torture, cli->session, "hideunread",
 145                                      &hideunread);
 146         if (!NT_STATUS_IS_OK(status)) {
 147                 d_printf("second_tcon(hideunread) failed: %s\n",
 148                          nt_errstr(status));
 149                 return false;
 150         }
 151 
 152         status = torture_second_tcon(torture, cli->session, "hideunwrite",
 153                                      &hideunwrite);
 154         if (!NT_STATUS_IS_OK(status)) {
 155                 d_printf("second_tcon(hideunwrite) failed: %s\n",
 156                          nt_errstr(status));
 157                 return false;
 158         }
 159 
 160         status = smbcli_unlink(cli->tree, fname);
 161         if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) {
 162                 smbcli_setatr(cli->tree, fname, 0, -1);
 163                 smbcli_unlink(cli->tree, fname);
 164         }
 165 
 166         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
 167         if (fnum == -1) {
 168                 d_printf("Failed to create %s - %s\n", fname,
 169                          smbcli_errstr(cli->tree));
 170                 return false;
 171         }
 172 
 173         smbcli_close(cli->tree, fnum);
 174 
 175         if (!smbcli_file_exists(cli->tree, fname)) {
 176                 d_printf("%s does not exist\n", fname);
 177                 return false;
 178         }
 179 
 180         /* R/W file should be visible everywhere */
 181 
 182         status = smbcli_chmod(cli->tree, fname, UNIX_R_USR|UNIX_W_USR);
 183         if (!NT_STATUS_IS_OK(status)) {
 184                 d_printf("smbcli_chmod failed: %s\n", nt_errstr(status));
 185                 return false;
 186         }
 187         if (!is_writeable(torture, cli->tree, fname)) {
 188                 d_printf("File not writable\n");
 189                 return false;
 190         }
 191         if (!is_readable(cli->tree, fname)) {
 192                 d_printf("File not readable\n");
 193                 return false;
 194         }
 195         if (!is_visible(cli->tree, fname)) {
 196                 d_printf("r/w file not visible via normal share\n");
 197                 return false;
 198         }
 199         if (!is_visible(hideunread, fname)) {
 200                 d_printf("r/w file not visible via hide unreadable\n");
 201                 return false;
 202         }
 203         if (!is_visible(hideunwrite, fname)) {
 204                 d_printf("r/w file not visible via hide unwriteable\n");
 205                 return false;
 206         }
 207 
 208         /* R/O file should not be visible via hide unwriteable files */
 209 
 210         status = smbcli_chmod(cli->tree, fname, UNIX_R_USR);
 211 
 212         if (!NT_STATUS_IS_OK(status)) {
 213                 d_printf("smbcli_chmod failed: %s\n", nt_errstr(status));
 214                 return false;
 215         }
 216         if (is_writeable(torture, cli->tree, fname)) {
 217                 d_printf("r/o is writable\n");
 218                 return false;
 219         }
 220         if (!is_readable(cli->tree, fname)) {
 221                 d_printf("r/o not readable\n");
 222                 return false;
 223         }
 224         if (!is_visible(cli->tree, fname)) {
 225                 d_printf("r/o file not visible via normal share\n");
 226                 return false;
 227         }
 228         if (!is_visible(hideunread, fname)) {
 229                 d_printf("r/o file not visible via hide unreadable\n");
 230                 return false;
 231         }
 232         if (is_visible(hideunwrite, fname)) {
 233                 d_printf("r/o file visible via hide unwriteable\n");
 234                 return false;
 235         }
 236 
 237         /* inaccessible file should be only visible on normal share */
 238 
 239         status = smbcli_chmod(cli->tree, fname, 0);
 240         if (!NT_STATUS_IS_OK(status)) {
 241                 d_printf("smbcli_chmod failed: %s\n", nt_errstr(status));
 242                 return false;
 243         }
 244         if (is_writeable(torture, cli->tree, fname)) {
 245                 d_printf("inaccessible file is writable\n");
 246                 return false;
 247         }
 248         if (is_readable(cli->tree, fname)) {
 249                 d_printf("inaccessible file is readable\n");
 250                 return false;
 251         }
 252         if (!is_visible(cli->tree, fname)) {
 253                 d_printf("inaccessible file not visible via normal share\n");
 254                 return false;
 255         }
 256         if (is_visible(hideunread, fname)) {
 257                 d_printf("inaccessible file visible via hide unreadable\n");
 258                 return false;
 259         }
 260         if (is_visible(hideunwrite, fname)) {
 261                 d_printf("inaccessible file visible via hide unwriteable\n");
 262                 return false;
 263         }
 264 
 265         smbcli_chmod(cli->tree, fname, UNIX_R_USR|UNIX_W_USR);
 266         smbcli_unlink(cli->tree, fname);
 267         
 268         return true;
 269 }
 270 
 271 /*
 272  * Try to force smb_close to return an error. The only way I can think of is
 273  * to open a file with delete on close, chmod the parent dir to 000 and then
 274  * close. smb_close should return NT_STATUS_ACCESS_DENIED.
 275  */
 276 
 277 bool torture_samba3_closeerr(struct torture_context *tctx)
     /* [<][>][^][v][top][bottom][index][help] */
 278 {
 279         struct smbcli_state *cli = NULL;
 280         bool result = false;
 281         NTSTATUS status;
 282         const char *dname = "closeerr.dir";
 283         const char *fname = "closeerr.dir\\closerr.txt";
 284         int fnum;
 285 
 286         if (!torture_open_connection(&cli, tctx, 0)) {
 287                 goto fail;
 288         }
 289 
 290         smbcli_deltree(cli->tree, dname);
 291 
 292         torture_assert_ntstatus_ok(
 293                 tctx, smbcli_mkdir(cli->tree, dname),
 294                 talloc_asprintf(tctx, "smbcli_mdir failed: (%s)\n",
 295                                 smbcli_errstr(cli->tree)));
 296 
 297         fnum = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR,
 298                             DENY_NONE);
 299         torture_assert(tctx, fnum != -1, 
 300                        talloc_asprintf(tctx, "smbcli_open failed: %s\n",
 301                                        smbcli_errstr(cli->tree)));
 302         smbcli_close(cli->tree, fnum);
 303 
 304         fnum = smbcli_nt_create_full(cli->tree, fname, 0, 
 305                                       SEC_RIGHTS_FILE_ALL,
 306                                       FILE_ATTRIBUTE_NORMAL,
 307                                       NTCREATEX_SHARE_ACCESS_DELETE,
 308                                       NTCREATEX_DISP_OPEN, 0, 0);
 309 
 310         torture_assert(tctx, fnum != -1, 
 311                        talloc_asprintf(tctx, "smbcli_open failed: %s\n",
 312                                        smbcli_errstr(cli->tree)));
 313 
 314         status = smbcli_nt_delete_on_close(cli->tree, fnum, true);
 315 
 316         torture_assert_ntstatus_ok(tctx, status, 
 317                                    "setting delete_on_close on file failed !");
 318 
 319         status = smbcli_chmod(cli->tree, dname, 0);
 320 
 321         torture_assert_ntstatus_ok(tctx, status, 
 322                                    "smbcli_chmod on file failed !");
 323 
 324         status = smbcli_close(cli->tree, fnum);
 325 
 326         smbcli_chmod(cli->tree, dname, UNIX_R_USR|UNIX_W_USR|UNIX_X_USR);
 327         smbcli_deltree(cli->tree, dname);
 328 
 329         torture_assert_ntstatus_equal(tctx, status, NT_STATUS_ACCESS_DENIED,
 330                                       "smbcli_close");
 331 
 332         result = true;
 333         
 334  fail:
 335         if (cli) {
 336                 torture_close_connection(cli);
 337         }
 338         return result;
 339 }

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