Line data Source code
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 "system/time.h"
22 : #include "system/filesys.h"
23 : #include "libcli/libcli.h"
24 : #include "torture/util.h"
25 : #include "torture/raw/proto.h"
26 :
27 14 : static void init_unixinfo_nochange(union smb_setfileinfo *info)
28 : {
29 14 : ZERO_STRUCTP(info);
30 14 : info->unix_basic.level = RAW_SFILEINFO_UNIX_BASIC;
31 14 : info->unix_basic.in.mode = SMB_MODE_NO_CHANGE;
32 :
33 14 : info->unix_basic.in.end_of_file = SMB_SIZE_NO_CHANGE_HI;
34 14 : info->unix_basic.in.end_of_file <<= 32;
35 14 : info->unix_basic.in.end_of_file |= SMB_SIZE_NO_CHANGE_LO;
36 :
37 14 : info->unix_basic.in.num_bytes = SMB_SIZE_NO_CHANGE_HI;
38 14 : info->unix_basic.in.num_bytes <<= 32;
39 14 : info->unix_basic.in.num_bytes |= SMB_SIZE_NO_CHANGE_LO;
40 :
41 14 : info->unix_basic.in.status_change_time = SMB_TIME_NO_CHANGE_HI;
42 14 : info->unix_basic.in.status_change_time <<= 32;
43 14 : info->unix_basic.in.status_change_time |= SMB_TIME_NO_CHANGE_LO;
44 :
45 14 : info->unix_basic.in.access_time = SMB_TIME_NO_CHANGE_HI;
46 14 : info->unix_basic.in.access_time <<= 32;
47 14 : info->unix_basic.in.access_time |= SMB_TIME_NO_CHANGE_LO;
48 :
49 14 : info->unix_basic.in.change_time = SMB_TIME_NO_CHANGE_HI;
50 14 : info->unix_basic.in.change_time <<= 32;
51 14 : info->unix_basic.in.change_time |= SMB_TIME_NO_CHANGE_LO;
52 :
53 14 : info->unix_basic.in.uid = SMB_UID_NO_CHANGE;
54 14 : info->unix_basic.in.gid = SMB_GID_NO_CHANGE;
55 14 : }
56 :
57 : struct list_state {
58 : const char *fname;
59 : bool visible;
60 : };
61 :
62 246 : static void set_visible(struct clilist_file_info *i, const char *mask,
63 : void *priv)
64 : {
65 246 : struct list_state *state = (struct list_state *)priv;
66 :
67 246 : if (strcasecmp_m(state->fname, i->name) == 0)
68 12 : state->visible = true;
69 246 : }
70 :
71 18 : static bool is_visible(struct smbcli_tree *tree, const char *fname)
72 : {
73 0 : struct list_state state;
74 :
75 18 : state.visible = false;
76 18 : state.fname = fname;
77 :
78 18 : if (smbcli_list(tree, "*.*", 0, set_visible, &state) < 0) {
79 0 : return false;
80 : }
81 18 : return state.visible;
82 : }
83 :
84 6 : static bool is_readable(struct smbcli_tree *tree, const char *fname)
85 : {
86 0 : int fnum;
87 6 : fnum = smbcli_open(tree, fname, O_RDONLY, DENY_NONE);
88 6 : if (fnum < 0) {
89 2 : return false;
90 : }
91 4 : smbcli_close(tree, fnum);
92 4 : return true;
93 : }
94 :
95 6 : static bool is_writeable(TALLOC_CTX *mem_ctx, struct smbcli_tree *tree,
96 : const char *fname)
97 : {
98 0 : int fnum;
99 6 : fnum = smbcli_open(tree, fname, O_WRONLY, DENY_NONE);
100 6 : if (fnum < 0) {
101 4 : return false;
102 : }
103 2 : smbcli_close(tree, fnum);
104 2 : return true;
105 : }
106 :
107 : /*
108 : * This is not an exact method because there's a ton of reasons why a getatr
109 : * might fail. But for our purposes it's sufficient.
110 : */
111 :
112 2 : static bool smbcli_file_exists(struct smbcli_tree *tree, const char *fname)
113 : {
114 2 : return NT_STATUS_IS_OK(smbcli_getatr(tree, fname, NULL, NULL, NULL));
115 : }
116 :
117 4 : static NTSTATUS smbcli_setup_unix(struct smbcli_tree *tree)
118 : {
119 0 : union smb_fsinfo fsinfo;
120 0 : union smb_setfsinfo set_fsinfo;
121 0 : NTSTATUS status;
122 :
123 4 : ZERO_STRUCT(fsinfo);
124 4 : ZERO_STRUCT(set_fsinfo);
125 :
126 4 : fsinfo.generic.level = RAW_QFS_UNIX_INFO;
127 4 : status = smb_raw_fsinfo(tree, NULL, &fsinfo);
128 4 : if (!NT_STATUS_IS_OK(status)) {
129 0 : printf("smb_raw_fsinfo failed %s\n",
130 : nt_errstr(status));
131 0 : return status;
132 : }
133 :
134 4 : set_fsinfo.generic.level = RAW_SETFS_UNIX_INFO;
135 4 : set_fsinfo.unix_info.in.major_version = fsinfo.unix_info.out.major_version;
136 4 : set_fsinfo.unix_info.in.minor_version = fsinfo.unix_info.out.minor_version;
137 4 : set_fsinfo.unix_info.in.capability = fsinfo.unix_info.out.capability;
138 :
139 4 : status = smb_raw_setfsinfo(tree, NULL, &set_fsinfo);
140 4 : if (!NT_STATUS_IS_OK(status)) {
141 0 : printf("smb_raw_setfsinfo failed %s\n",
142 : nt_errstr(status));
143 : }
144 4 : return status;
145 : }
146 :
147 14 : static NTSTATUS smbcli_chmod(struct smbcli_tree *tree, const char *fname,
148 : uint64_t permissions)
149 : {
150 0 : union smb_setfileinfo sfinfo;
151 14 : init_unixinfo_nochange(&sfinfo);
152 14 : sfinfo.unix_basic.in.file.path = fname;
153 14 : sfinfo.unix_basic.in.permissions = permissions;
154 14 : return smb_raw_setpathinfo(tree, &sfinfo);
155 : }
156 :
157 4 : bool torture_samba3_hide(struct torture_context *torture, struct smbcli_state *cli)
158 : {
159 4 : const char *fname = "torture_samba3_hide.txt";
160 0 : int fnum;
161 0 : NTSTATUS status;
162 0 : struct smbcli_tree *hideunread;
163 0 : struct smbcli_tree *hideunwrite;
164 :
165 4 : status = smbcli_setup_unix(cli->tree);
166 4 : if (!NT_STATUS_IS_OK(status)) {
167 0 : torture_fail(torture,
168 : talloc_asprintf(torture, "smbcli_setup_unix failed %s\n",
169 : nt_errstr(status)));
170 : }
171 :
172 4 : status = torture_second_tcon(torture, cli->session, "hideunread",
173 : &hideunread);
174 4 : torture_assert_ntstatus_ok(torture, status, "second_tcon(hideunread) failed\n");
175 :
176 4 : status = torture_second_tcon(torture, cli->session, "hideunwrite",
177 : &hideunwrite);
178 4 : torture_assert_ntstatus_ok(torture, status, "second_tcon(hideunwrite) failed\n");
179 :
180 2 : status = smbcli_unlink(cli->tree, fname);
181 2 : if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) {
182 0 : smbcli_setatr(cli->tree, fname, 0, -1);
183 0 : smbcli_unlink(cli->tree, fname);
184 : }
185 :
186 2 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
187 2 : if (fnum == -1) {
188 0 : torture_fail(torture,
189 : talloc_asprintf(torture, "Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)));
190 : }
191 :
192 2 : smbcli_close(cli->tree, fnum);
193 :
194 2 : if (!smbcli_file_exists(cli->tree, fname)) {
195 0 : torture_fail(torture, talloc_asprintf(torture, "%s does not exist\n", fname));
196 : }
197 :
198 : /* R/W file should be visible everywhere */
199 :
200 2 : status = smbcli_chmod(cli->tree, fname, UNIX_R_USR|UNIX_W_USR);
201 2 : torture_assert_ntstatus_ok(torture, status, "smbcli_chmod failed\n");
202 :
203 2 : if (!is_writeable(torture, cli->tree, fname)) {
204 0 : torture_fail(torture, "File not writable\n");
205 : }
206 2 : if (!is_readable(cli->tree, fname)) {
207 0 : torture_fail(torture, "File not readable\n");
208 : }
209 2 : if (!is_visible(cli->tree, fname)) {
210 0 : torture_fail(torture, "r/w file not visible via normal share\n");
211 : }
212 2 : if (!is_visible(hideunread, fname)) {
213 0 : torture_fail(torture, "r/w file not visible via hide unreadable\n");
214 : }
215 2 : if (!is_visible(hideunwrite, fname)) {
216 0 : torture_fail(torture, "r/w file not visible via hide unwriteable\n");
217 : }
218 :
219 : /* R/O file should not be visible via hide unwriteable files */
220 :
221 2 : status = smbcli_chmod(cli->tree, fname, UNIX_R_USR);
222 2 : torture_assert_ntstatus_ok(torture, status, "smbcli_chmod failed\n");
223 :
224 2 : if (is_writeable(torture, cli->tree, fname)) {
225 0 : torture_fail(torture, "r/o is writable\n");
226 : }
227 2 : if (!is_readable(cli->tree, fname)) {
228 0 : torture_fail(torture, "r/o not readable\n");
229 : }
230 2 : if (!is_visible(cli->tree, fname)) {
231 0 : torture_fail(torture, "r/o file not visible via normal share\n");
232 : }
233 2 : if (!is_visible(hideunread, fname)) {
234 0 : torture_fail(torture, "r/o file not visible via hide unreadable\n");
235 : }
236 2 : if (is_visible(hideunwrite, fname)) {
237 0 : torture_fail(torture, "r/o file visible via hide unwriteable\n");
238 : }
239 :
240 : /* inaccessible file should be only visible on normal share */
241 :
242 2 : status = smbcli_chmod(cli->tree, fname, 0);
243 2 : torture_assert_ntstatus_ok(torture, status, "smbcli_chmod failed\n");
244 :
245 2 : if (is_writeable(torture, cli->tree, fname)) {
246 0 : torture_fail(torture, "inaccessible file is writable\n");
247 : }
248 2 : if (is_readable(cli->tree, fname)) {
249 0 : torture_fail(torture, "inaccessible file is readable\n");
250 : }
251 2 : if (!is_visible(cli->tree, fname)) {
252 0 : torture_fail(torture, "inaccessible file not visible via normal share\n");
253 : }
254 2 : if (is_visible(hideunread, fname)) {
255 0 : torture_fail(torture, "inaccessible file visible via hide unreadable\n");
256 : }
257 2 : if (is_visible(hideunwrite, fname)) {
258 0 : torture_fail(torture, "inaccessible file visible via hide unwriteable\n");
259 : }
260 :
261 2 : smbcli_chmod(cli->tree, fname, UNIX_R_USR|UNIX_W_USR);
262 2 : smbcli_unlink(cli->tree, fname);
263 :
264 2 : return true;
265 : }
266 :
267 : /*
268 : * Try to force smb_close to return an error. The only way I can think of is
269 : * to open a file with delete on close, chmod the parent dir to 000 and then
270 : * close. smb_close should return NT_STATUS_ACCESS_DENIED.
271 : */
272 :
273 6 : bool torture_samba3_closeerr(struct torture_context *tctx, struct smbcli_state *cli)
274 : {
275 6 : bool result = false;
276 0 : NTSTATUS status;
277 6 : const char *dname = "closeerr.dir";
278 6 : const char *fname = "closeerr.dir\\closerr.txt";
279 0 : int fnum;
280 :
281 6 : smbcli_deltree(cli->tree, dname);
282 :
283 6 : torture_assert_ntstatus_ok(
284 : tctx, smbcli_mkdir(cli->tree, dname),
285 : talloc_asprintf(tctx, "smbcli_mdir failed: (%s)\n",
286 : smbcli_errstr(cli->tree)));
287 :
288 6 : fnum = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR,
289 : DENY_NONE);
290 6 : torture_assert(tctx, fnum != -1,
291 : talloc_asprintf(tctx, "smbcli_open failed: %s\n",
292 : smbcli_errstr(cli->tree)));
293 6 : smbcli_close(cli->tree, fnum);
294 :
295 6 : fnum = smbcli_nt_create_full(cli->tree, fname, 0,
296 : SEC_RIGHTS_FILE_ALL,
297 : FILE_ATTRIBUTE_NORMAL,
298 : NTCREATEX_SHARE_ACCESS_DELETE,
299 : NTCREATEX_DISP_OPEN, 0, 0);
300 :
301 6 : torture_assert(tctx, fnum != -1,
302 : talloc_asprintf(tctx, "smbcli_open failed: %s\n",
303 : smbcli_errstr(cli->tree)));
304 :
305 6 : status = smbcli_nt_delete_on_close(cli->tree, fnum, true);
306 :
307 6 : torture_assert_ntstatus_ok(tctx, status,
308 : "setting delete_on_close on file failed !");
309 :
310 6 : status = smbcli_chmod(cli->tree, dname, 0);
311 :
312 6 : torture_assert_ntstatus_ok(tctx, status,
313 : "smbcli_chmod on file failed !");
314 :
315 0 : status = smbcli_close(cli->tree, fnum);
316 :
317 0 : smbcli_chmod(cli->tree, dname, UNIX_R_USR|UNIX_W_USR|UNIX_X_USR);
318 0 : smbcli_deltree(cli->tree, dname);
319 :
320 0 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_ACCESS_DENIED,
321 : "smbcli_close");
322 :
323 0 : result = true;
324 :
325 0 : return result;
326 : }
|