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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "torture/torture.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "system/time.h"
25 #include "system/filesys.h"
26 #include "libcli/libcli.h"
27 #include "torture/util.h"
28
init_unixinfo_nochange(union smb_setfileinfo * info)29 static void init_unixinfo_nochange(union smb_setfileinfo *info)
30 {
31 ZERO_STRUCTP(info);
32 info->unix_basic.level = RAW_SFILEINFO_UNIX_BASIC;
33 info->unix_basic.in.mode = SMB_MODE_NO_CHANGE;
34
35 info->unix_basic.in.end_of_file = SMB_SIZE_NO_CHANGE_HI;
36 info->unix_basic.in.end_of_file <<= 32;
37 info->unix_basic.in.end_of_file |= SMB_SIZE_NO_CHANGE_LO;
38
39 info->unix_basic.in.num_bytes = SMB_SIZE_NO_CHANGE_HI;
40 info->unix_basic.in.num_bytes <<= 32;
41 info->unix_basic.in.num_bytes |= SMB_SIZE_NO_CHANGE_LO;
42
43 info->unix_basic.in.status_change_time = SMB_TIME_NO_CHANGE_HI;
44 info->unix_basic.in.status_change_time <<= 32;
45 info->unix_basic.in.status_change_time = SMB_TIME_NO_CHANGE_LO;
46
47 info->unix_basic.in.access_time = SMB_TIME_NO_CHANGE_HI;
48 info->unix_basic.in.access_time <<= 32;
49 info->unix_basic.in.access_time |= SMB_TIME_NO_CHANGE_LO;
50
51 info->unix_basic.in.change_time = SMB_TIME_NO_CHANGE_HI;
52 info->unix_basic.in.change_time <<= 32;
53 info->unix_basic.in.change_time |= SMB_TIME_NO_CHANGE_LO;
54
55 info->unix_basic.in.uid = SMB_UID_NO_CHANGE;
56 info->unix_basic.in.gid = SMB_GID_NO_CHANGE;
57 }
58
59 struct list_state {
60 const char *fname;
61 BOOL visible;
62 };
63
set_visible(struct clilist_file_info * i,const char * mask,void * priv)64 static void set_visible(struct clilist_file_info *i, const char *mask,
65 void *priv)
66 {
67 struct list_state *state = priv;
68
69 if (strcasecmp_m(state->fname, i->name) == 0)
70 state->visible = True;
71 }
72
is_visible(struct smbcli_tree * tree,const char * fname)73 static BOOL is_visible(struct smbcli_tree *tree, const char *fname)
74 {
75 struct list_state state;
76
77 state.visible = False;
78 state.fname = fname;
79
80 if (smbcli_list(tree, "*.*", 0, set_visible, &state) < 0) {
81 return False;
82 }
83 return state.visible;
84 }
85
is_readable(struct smbcli_tree * tree,const char * fname)86 static BOOL is_readable(struct smbcli_tree *tree, const char *fname)
87 {
88 int fnum;
89 fnum = smbcli_open(tree, fname, O_RDONLY, DENY_NONE);
90 if (fnum < 0) {
91 return False;
92 }
93 smbcli_close(tree, fnum);
94 return True;
95 }
96
is_writeable(TALLOC_CTX * mem_ctx,struct smbcli_tree * tree,const char * fname)97 static BOOL is_writeable(TALLOC_CTX *mem_ctx, struct smbcli_tree *tree,
98 const char *fname)
99 {
100 int fnum;
101 fnum = smbcli_open(tree, fname, O_WRONLY, DENY_NONE);
102 if (fnum < 0) {
103 return False;
104 }
105 smbcli_close(tree, fnum);
106 return True;
107 }
108
109 /*
110 * This is not an exact method because there's a ton of reasons why a getatr
111 * might fail. But for our purposes it's sufficient.
112 */
113
smbcli_file_exists(struct smbcli_tree * tree,const char * fname)114 static BOOL smbcli_file_exists(struct smbcli_tree *tree, const char *fname)
115 {
116 return NT_STATUS_IS_OK(smbcli_getatr(tree, fname, NULL, NULL, NULL));
117 }
118
smbcli_chmod(struct smbcli_tree * tree,const char * fname,uint64_t permissions)119 static NTSTATUS smbcli_chmod(struct smbcli_tree *tree, const char *fname,
120 uint64_t permissions)
121 {
122 union smb_setfileinfo sfinfo;
123 init_unixinfo_nochange(&sfinfo);
124 sfinfo.unix_basic.in.file.path = fname;
125 sfinfo.unix_basic.in.permissions = permissions;
126 return smb_raw_setpathinfo(tree, &sfinfo);
127 }
128
torture_samba3_hide(struct torture_context * torture)129 BOOL torture_samba3_hide(struct torture_context *torture)
130 {
131 struct smbcli_state *cli;
132 const char *fname = "test.txt";
133 int fnum;
134 NTSTATUS status;
135 struct smbcli_tree *hideunread;
136 struct smbcli_tree *hideunwrite;
137
138 if (!torture_open_connection_share(
139 torture, &cli, torture_setting_string(torture, "host", NULL),
140 torture_setting_string(torture, "share", NULL), NULL)) {
141 d_printf("torture_open_connection_share failed\n");
142 return False;
143 }
144
145 status = torture_second_tcon(torture, cli->session, "hideunread",
146 &hideunread);
147 if (!NT_STATUS_IS_OK(status)) {
148 d_printf("second_tcon(hideunread) failed: %s\n",
149 nt_errstr(status));
150 return False;
151 }
152
153 status = torture_second_tcon(torture, cli->session, "hideunwrite",
154 &hideunwrite);
155 if (!NT_STATUS_IS_OK(status)) {
156 d_printf("second_tcon(hideunwrite) failed: %s\n",
157 nt_errstr(status));
158 return False;
159 }
160
161 status = smbcli_unlink(cli->tree, fname);
162 if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) {
163 smbcli_setatr(cli->tree, fname, 0, -1);
164 smbcli_unlink(cli->tree, fname);
165 }
166
167 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
168 if (fnum == -1) {
169 d_printf("Failed to create %s - %s\n", fname,
170 smbcli_errstr(cli->tree));
171 return False;
172 }
173
174 smbcli_close(cli->tree, fnum);
175
176 if (!smbcli_file_exists(cli->tree, fname)) {
177 d_printf("%s does not exist\n", fname);
178 return False;
179 }
180
181 /* R/W file should be visible everywhere */
182
183 status = smbcli_chmod(cli->tree, fname, UNIX_R_USR|UNIX_W_USR);
184 if (!NT_STATUS_IS_OK(status)) {
185 d_printf("smbcli_chmod failed: %s\n", nt_errstr(status));
186 return False;
187 }
188 if (!is_writeable(torture, cli->tree, fname)) {
189 d_printf("File not writable\n");
190 return False;
191 }
192 if (!is_readable(cli->tree, fname)) {
193 d_printf("File not readable\n");
194 return False;
195 }
196 if (!is_visible(cli->tree, fname)) {
197 d_printf("r/w file not visible via normal share\n");
198 return False;
199 }
200 if (!is_visible(hideunread, fname)) {
201 d_printf("r/w file not visible via hide unreadable\n");
202 return False;
203 }
204 if (!is_visible(hideunwrite, fname)) {
205 d_printf("r/w file not visible via hide unwriteable\n");
206 return False;
207 }
208
209 /* R/O file should not be visible via hide unwriteable files */
210
211 status = smbcli_chmod(cli->tree, fname, UNIX_R_USR);
212
213 if (!NT_STATUS_IS_OK(status)) {
214 d_printf("smbcli_chmod failed: %s\n", nt_errstr(status));
215 return False;
216 }
217 if (is_writeable(torture, cli->tree, fname)) {
218 d_printf("r/o is writable\n");
219 return False;
220 }
221 if (!is_readable(cli->tree, fname)) {
222 d_printf("r/o not readable\n");
223 return False;
224 }
225 if (!is_visible(cli->tree, fname)) {
226 d_printf("r/o file not visible via normal share\n");
227 return False;
228 }
229 if (!is_visible(hideunread, fname)) {
230 d_printf("r/o file not visible via hide unreadable\n");
231 return False;
232 }
233 if (is_visible(hideunwrite, fname)) {
234 d_printf("r/o file visible via hide unwriteable\n");
235 return False;
236 }
237
238 /* inaccessible file should be only visible on normal share */
239
240 status = smbcli_chmod(cli->tree, fname, 0);
241 if (!NT_STATUS_IS_OK(status)) {
242 d_printf("smbcli_chmod failed: %s\n", nt_errstr(status));
243 return False;
244 }
245 if (is_writeable(torture, cli->tree, fname)) {
246 d_printf("inaccessible file is writable\n");
247 return False;
248 }
249 if (is_readable(cli->tree, fname)) {
250 d_printf("inaccessible file is readable\n");
251 return False;
252 }
253 if (!is_visible(cli->tree, fname)) {
254 d_printf("inaccessible file not visible via normal share\n");
255 return False;
256 }
257 if (is_visible(hideunread, fname)) {
258 d_printf("inaccessible file visible via hide unreadable\n");
259 return False;
260 }
261 if (is_visible(hideunwrite, fname)) {
262 d_printf("inaccessible file visible via hide unwriteable\n");
263 return False;
264 }
265
266 return True;
267 }
268