Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Copyright (C) Ralph Boehme 2020
4 :
5 : This program is free software; you can redistribute it and/or modify
6 : it under the terms of the GNU General Public License as published by
7 : the Free Software Foundation; either version 3 of the License, or
8 : (at your option) any later version.
9 :
10 : This program is distributed in the hope that it will be useful,
11 : but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU General Public License for more details.
14 :
15 : You should have received a copy of the GNU General Public License
16 : along with this program. If not, see <http://www.gnu.org/licenses/>.
17 : */
18 :
19 : #include "includes.h"
20 : #include "torture/proto.h"
21 : #include "libcli/security/security.h"
22 : #include "libsmb/libsmb.h"
23 : #include "libsmb/clirap.h"
24 : #include "libsmb/proto.h"
25 : #include "../libcli/smb/smbXcli_base.h"
26 : #include "util_sd.h"
27 : #include "trans2.h"
28 :
29 : extern struct cli_credentials *torture_creds;
30 : extern fstring host, workgroup, share, password, username, myname;
31 :
32 : struct posix_test_entry {
33 : const char *name;
34 : const char *target;
35 : const char *expected;
36 : uint32_t attr_win;
37 : uint32_t attr_lin;
38 : uint64_t returned_size;
39 : bool ok;
40 : };
41 :
42 : enum client_flavour { WINDOWS, POSIX };
43 :
44 : struct posix_test_state {
45 : enum client_flavour flavour;
46 : struct posix_test_entry *entries;
47 : };
48 :
49 176 : static NTSTATUS posix_ls_fn(struct file_info *finfo,
50 : const char *name,
51 : void *_state)
52 : {
53 176 : struct posix_test_state *state =
54 : (struct posix_test_state *)_state;
55 176 : struct posix_test_entry *e = state->entries;
56 :
57 752 : for (; e->name != NULL; e++) {
58 0 : uint32_t attr;
59 624 : if (!strequal(finfo->name, e->expected)) {
60 576 : continue;
61 : }
62 48 : if (state->flavour == WINDOWS) {
63 16 : attr = e->attr_win;
64 : } else {
65 32 : attr = e->attr_lin;
66 : }
67 48 : if (attr != finfo->attr) {
68 0 : break;
69 : }
70 48 : e->ok = true;
71 48 : e->returned_size = finfo->size;
72 48 : break;
73 : }
74 :
75 176 : return NT_STATUS_OK;
76 : }
77 :
78 8 : static void posix_test_entries_reset(struct posix_test_state *state)
79 : {
80 8 : struct posix_test_entry *e = state->entries;
81 :
82 40 : for (; e->name != NULL; e++) {
83 32 : e->ok = false;
84 32 : e->returned_size = 0;
85 : }
86 8 : }
87 :
88 88 : static bool posix_test_entry_check(struct posix_test_state *state,
89 : const char *name,
90 : bool expected,
91 : uint64_t expected_size)
92 : {
93 88 : struct posix_test_entry *e = state->entries;
94 88 : bool result = false;
95 :
96 208 : for (; e->name != NULL; e++) {
97 208 : if (strequal(name, e->name)) {
98 88 : result = e->ok;
99 88 : break;
100 : }
101 : }
102 88 : if (e->name == NULL) {
103 0 : printf("test failed, unknown name: %s\n", name);
104 0 : return false;
105 : }
106 :
107 88 : if (expected == result) {
108 88 : return true;
109 : }
110 :
111 0 : printf("test failed, %s: %s\n",
112 : expected ? "missing" : "unexpected",
113 : name);
114 :
115 0 : return false;
116 : }
117 :
118 : /*
119 : Test non-POSIX vs POSIX ls * of symlinks
120 : */
121 4 : bool run_posix_ls_wildcard_test(int dummy)
122 : {
123 4 : TALLOC_CTX *frame = NULL;
124 4 : struct cli_state *cli_unix = NULL;
125 4 : struct cli_state *cli_win = NULL;
126 4 : uint16_t fnum = (uint16_t)-1;
127 0 : NTSTATUS status;
128 4 : const char *file = "file";
129 4 : const char *symlnk_dangling = "dangling";
130 4 : const char *symlnk_dst_dangling = "xxxxxxx";
131 4 : const char *symlnk_in_share = "symlnk_in_share";
132 4 : const char *symlnk_dst_in_share = file;
133 4 : const char *symlnk_outside_share = "symlnk_outside_share";
134 4 : const char *symlnk_dst_outside_share = "/etc/passwd";
135 4 : struct posix_test_entry entries[] = {
136 : {
137 : .name = file,
138 : .target = NULL,
139 : .expected = file,
140 : .attr_win = FILE_ATTRIBUTE_ARCHIVE,
141 : .attr_lin = FILE_ATTRIBUTE_ARCHIVE,
142 : }, {
143 : .name = symlnk_dangling,
144 : .target = symlnk_dst_dangling,
145 : .expected = symlnk_dangling,
146 : .attr_win = FILE_ATTRIBUTE_INVALID,
147 : .attr_lin = FILE_ATTRIBUTE_NORMAL,
148 : }, {
149 : .name = symlnk_in_share,
150 : .target = symlnk_dst_in_share,
151 : .expected = symlnk_in_share,
152 : .attr_win = FILE_ATTRIBUTE_ARCHIVE,
153 : .attr_lin = FILE_ATTRIBUTE_NORMAL,
154 : }, {
155 : .name = symlnk_outside_share,
156 : .target = symlnk_dst_outside_share,
157 : .expected = symlnk_outside_share,
158 : .attr_win = FILE_ATTRIBUTE_INVALID,
159 : .attr_lin = FILE_ATTRIBUTE_NORMAL,
160 : }, {
161 : .name = NULL,
162 : }
163 : };
164 4 : struct posix_test_state _state = {
165 : .entries = entries,
166 : };
167 4 : struct posix_test_state *state = &_state;
168 0 : int i;
169 4 : bool correct = false;
170 :
171 4 : frame = talloc_stackframe();
172 :
173 4 : printf("Starting POSIX-LS-WILDCARD test\n");
174 :
175 4 : if (!torture_open_connection(&cli_unix, 0)) {
176 0 : TALLOC_FREE(frame);
177 0 : return false;
178 : }
179 :
180 4 : if (!torture_open_connection(&cli_win, 0)) {
181 0 : TALLOC_FREE(frame);
182 0 : return false;
183 : }
184 :
185 4 : torture_conn_set_sockopt(cli_unix);
186 4 : torture_conn_set_sockopt(cli_win);
187 :
188 4 : status = torture_setup_unix_extensions(cli_unix);
189 4 : if (!NT_STATUS_IS_OK(status)) {
190 0 : TALLOC_FREE(frame);
191 0 : return false;
192 : }
193 :
194 4 : cli_posix_unlink(cli_unix, file);
195 4 : cli_posix_unlink(cli_unix, symlnk_dangling);
196 4 : cli_posix_unlink(cli_unix, symlnk_in_share);
197 4 : cli_posix_unlink(cli_unix, symlnk_outside_share);
198 :
199 4 : status = cli_posix_open(cli_unix,
200 : file,
201 : O_RDWR|O_CREAT,
202 : 0666,
203 : &fnum);
204 4 : if (!NT_STATUS_IS_OK(status)) {
205 0 : printf("cli_posix_open of %s failed error %s\n",
206 : file,
207 : nt_errstr(status));
208 0 : goto out;
209 : }
210 :
211 4 : status = cli_close(cli_unix, fnum);
212 4 : if (!NT_STATUS_IS_OK(status)) {
213 0 : printf("cli_close failed %s\n", nt_errstr(status));
214 0 : goto out;
215 : }
216 4 : fnum = (uint16_t)-1;
217 :
218 20 : for (i = 0; entries[i].name != NULL; i++) {
219 16 : if (entries[i].target == NULL) {
220 4 : continue;
221 : }
222 12 : status = cli_posix_symlink(cli_unix,
223 : entries[i].target,
224 : entries[i].name);
225 12 : if (!NT_STATUS_IS_OK(status)) {
226 0 : printf("POSIX symlink of %s failed (%s)\n",
227 : entries[i].name, nt_errstr(status));
228 0 : goto out;
229 : }
230 : }
231 :
232 4 : printf("Doing Windows ls *\n");
233 4 : state->flavour = WINDOWS;
234 :
235 4 : status = cli_list(cli_win, "*", 0, posix_ls_fn, state);
236 4 : if (!NT_STATUS_IS_OK(status)) {
237 0 : printf("cli_list failed %s\n", nt_errstr(status));
238 0 : goto out;
239 : }
240 :
241 4 : if (!posix_test_entry_check(state, file, true, 0)) {
242 0 : goto out;
243 : }
244 4 : if (!posix_test_entry_check(state, symlnk_dangling, false, 0)) {
245 0 : goto out;
246 : }
247 4 : if (!posix_test_entry_check(state, symlnk_outside_share, false, 0)) {
248 0 : goto out;
249 : }
250 4 : if (!posix_test_entry_check(state, symlnk_in_share, true, 0)) {
251 0 : goto out;
252 : }
253 :
254 4 : posix_test_entries_reset(state);
255 :
256 4 : printf("Doing POSIX ls *\n");
257 4 : state->flavour = POSIX;
258 :
259 4 : status = cli_list(cli_unix, "*", 0, posix_ls_fn, state);
260 4 : if (!NT_STATUS_IS_OK(status)) {
261 0 : printf("cli_close failed %s\n", nt_errstr(status));
262 0 : goto out;
263 : }
264 :
265 4 : if (!posix_test_entry_check(state, file, true, 0)) {
266 0 : goto out;
267 : }
268 4 : if (!posix_test_entry_check(state,
269 : symlnk_dangling,
270 : true,
271 : strlen(symlnk_dst_dangling)))
272 : {
273 0 : goto out;
274 : }
275 4 : if (!posix_test_entry_check(state,
276 : symlnk_outside_share,
277 : true,
278 : strlen(symlnk_dst_outside_share)))
279 : {
280 0 : goto out;
281 : }
282 4 : if (!posix_test_entry_check(state,
283 : symlnk_in_share,
284 : true,
285 : strlen(symlnk_dst_in_share))) {
286 0 : goto out;
287 : }
288 :
289 4 : printf("POSIX-LS-WILDCARD test passed\n");
290 4 : correct = true;
291 :
292 4 : out:
293 4 : cli_posix_unlink(cli_unix, file);
294 4 : cli_posix_unlink(cli_unix, symlnk_dangling);
295 4 : cli_posix_unlink(cli_unix, symlnk_in_share);
296 4 : cli_posix_unlink(cli_unix, symlnk_outside_share);
297 :
298 4 : if (!torture_close_connection(cli_unix)) {
299 0 : correct = false;
300 : }
301 4 : if (!torture_close_connection(cli_win)) {
302 0 : correct = false;
303 : }
304 :
305 4 : TALLOC_FREE(frame);
306 4 : return correct;
307 : }
308 :
309 : /*
310 : Test non-POSIX vs POSIX ls single of symlinks
311 : */
312 4 : bool run_posix_ls_single_test(int dummy)
313 : {
314 4 : TALLOC_CTX *frame = NULL;
315 4 : struct cli_state *cli_unix = NULL;
316 4 : struct cli_state *cli_win = NULL;
317 4 : uint16_t fnum = (uint16_t)-1;
318 0 : NTSTATUS status;
319 4 : const char *file = "file";
320 4 : const char *symlnk_dangling = "dangling";
321 4 : const char *symlnk_dst_dangling = "xxxxxxx";
322 4 : const char *symlnk_in_share = "symlnk_in_share";
323 4 : const char *symlnk_dst_in_share = file;
324 4 : const char *symlnk_outside_share = "symlnk_outside_share";
325 4 : const char *symlnk_dst_outside_share = "/etc/passwd";
326 4 : struct posix_test_entry entries[] = {
327 : {
328 : .name = file,
329 : .target = NULL,
330 : .expected = file,
331 : .attr_win = FILE_ATTRIBUTE_ARCHIVE,
332 : .attr_lin = FILE_ATTRIBUTE_ARCHIVE,
333 : }, {
334 : .name = symlnk_dangling,
335 : .target = symlnk_dst_dangling,
336 : .expected = symlnk_dangling,
337 : .attr_win = FILE_ATTRIBUTE_INVALID,
338 : .attr_lin = FILE_ATTRIBUTE_NORMAL,
339 : }, {
340 : .name = symlnk_in_share,
341 : .target = symlnk_dst_in_share,
342 : .expected = symlnk_in_share,
343 : .attr_win = FILE_ATTRIBUTE_ARCHIVE,
344 : .attr_lin = FILE_ATTRIBUTE_NORMAL,
345 : }, {
346 : .name = symlnk_outside_share,
347 : .target = symlnk_dst_outside_share,
348 : .expected = symlnk_outside_share,
349 : .attr_win = FILE_ATTRIBUTE_INVALID,
350 : .attr_lin = FILE_ATTRIBUTE_NORMAL,
351 : }, {
352 : .name = NULL,
353 : }
354 : };
355 4 : struct posix_test_state _state = {
356 : .entries = &entries[0],
357 : };
358 4 : struct posix_test_state *state = &_state;
359 0 : int i;
360 4 : bool correct = false;
361 :
362 4 : frame = talloc_stackframe();
363 :
364 4 : printf("Starting POSIX-LS-SINGLE test\n");
365 :
366 4 : if (!torture_open_connection(&cli_unix, 0)) {
367 0 : TALLOC_FREE(frame);
368 0 : return false;
369 : }
370 :
371 4 : if (!torture_init_connection(&cli_win)) {
372 0 : TALLOC_FREE(frame);
373 0 : return false;
374 : }
375 :
376 4 : status = smbXcli_negprot(cli_win->conn,
377 4 : cli_win->timeout,
378 4 : lp_client_min_protocol(),
379 4 : lp_client_max_protocol(),
380 : NULL,
381 : NULL,
382 : NULL);
383 4 : if (!NT_STATUS_IS_OK(status)) {
384 0 : printf("smbXcli_negprot returned %s\n", nt_errstr(status));
385 0 : TALLOC_FREE(frame);
386 0 : return false;
387 : }
388 :
389 4 : status = cli_session_setup_creds(cli_win, torture_creds);
390 4 : if (!NT_STATUS_IS_OK(status)) {
391 0 : printf("smb2cli_sesssetup returned %s\n", nt_errstr(status));
392 0 : TALLOC_FREE(frame);
393 0 : return false;
394 : }
395 :
396 4 : status = cli_tree_connect(cli_win, share, "?????", NULL);
397 4 : if (!NT_STATUS_IS_OK(status)) {
398 0 : printf("cli_tree_connect returned %s\n", nt_errstr(status));
399 0 : TALLOC_FREE(frame);
400 0 : return false;
401 : }
402 4 : torture_conn_set_sockopt(cli_unix);
403 4 : torture_conn_set_sockopt(cli_win);
404 :
405 4 : status = torture_setup_unix_extensions(cli_unix);
406 4 : if (!NT_STATUS_IS_OK(status)) {
407 0 : TALLOC_FREE(frame);
408 0 : return false;
409 : }
410 :
411 4 : cli_posix_unlink(cli_unix, file);
412 4 : cli_posix_unlink(cli_unix, symlnk_dangling);
413 4 : cli_posix_unlink(cli_unix, symlnk_in_share);
414 4 : cli_posix_unlink(cli_unix, symlnk_outside_share);
415 :
416 4 : status = cli_posix_open(cli_unix,
417 : file,
418 : O_RDWR|O_CREAT,
419 : 0666,
420 : &fnum);
421 4 : if (!NT_STATUS_IS_OK(status)) {
422 0 : printf("cli_posix_open of %s failed error %s\n",
423 : file,
424 : nt_errstr(status));
425 0 : goto out;
426 : }
427 :
428 4 : status = cli_close(cli_unix, fnum);
429 4 : if (!NT_STATUS_IS_OK(status)) {
430 0 : printf("cli_close failed %s\n", nt_errstr(status));
431 0 : goto out;
432 : }
433 4 : fnum = (uint16_t)-1;
434 :
435 20 : for (i = 0; entries[i].name != NULL; i++) {
436 16 : if (entries[i].target == NULL) {
437 4 : continue;
438 : }
439 12 : status = cli_posix_symlink(cli_unix,
440 : entries[i].target,
441 : entries[i].name);
442 12 : if (!NT_STATUS_IS_OK(status)) {
443 0 : printf("POSIX symlink of %s failed (%s)\n",
444 : symlnk_dangling, nt_errstr(status));
445 0 : goto out;
446 : }
447 : }
448 :
449 4 : printf("Doing Windows ls single\n");
450 4 : state->flavour = WINDOWS;
451 :
452 4 : cli_list(cli_win, file, 0, posix_ls_fn, state);
453 4 : cli_list(cli_win, symlnk_dangling, 0, posix_ls_fn, state);
454 4 : cli_list(cli_win, symlnk_outside_share, 0, posix_ls_fn, state);
455 4 : cli_list(cli_win, symlnk_in_share, 0, posix_ls_fn, state);
456 :
457 4 : if (!posix_test_entry_check(state, file, true, 0)) {
458 0 : goto out;
459 : }
460 4 : if (!posix_test_entry_check(state, symlnk_dangling, false, 0)) {
461 0 : goto out;
462 : }
463 4 : if (!posix_test_entry_check(state, symlnk_outside_share, false, 0)) {
464 0 : goto out;
465 : }
466 4 : if (!posix_test_entry_check(state, symlnk_in_share, true, 0)) {
467 0 : goto out;
468 : }
469 :
470 4 : posix_test_entries_reset(state);
471 :
472 4 : printf("Doing POSIX ls single\n");
473 4 : state->flavour = POSIX;
474 :
475 4 : cli_list(cli_unix, file, 0, posix_ls_fn, state);
476 4 : cli_list(cli_unix, symlnk_dangling, 0, posix_ls_fn, state);
477 4 : cli_list(cli_unix, symlnk_outside_share, 0, posix_ls_fn, state);
478 4 : cli_list(cli_unix, symlnk_in_share, 0, posix_ls_fn, state);
479 :
480 4 : if (!posix_test_entry_check(state, file, true, 0)) {
481 0 : goto out;
482 : }
483 4 : if (!posix_test_entry_check(state,
484 : symlnk_dangling,
485 : true,
486 : strlen(symlnk_dst_dangling)))
487 : {
488 0 : goto out;
489 : }
490 4 : if (!posix_test_entry_check(state,
491 : symlnk_outside_share,
492 : true,
493 : strlen(symlnk_dst_outside_share)))
494 : {
495 0 : goto out;
496 : }
497 4 : if (!posix_test_entry_check(state,
498 : symlnk_in_share,
499 : true,
500 : strlen(symlnk_dst_in_share))) {
501 0 : goto out;
502 : }
503 :
504 4 : printf("POSIX-LS-SINGLE test passed\n");
505 4 : correct = true;
506 :
507 4 : out:
508 4 : cli_posix_unlink(cli_unix, file);
509 4 : cli_posix_unlink(cli_unix, symlnk_dangling);
510 4 : cli_posix_unlink(cli_unix, symlnk_in_share);
511 4 : cli_posix_unlink(cli_unix, symlnk_outside_share);
512 :
513 4 : if (!torture_close_connection(cli_unix)) {
514 0 : correct = false;
515 : }
516 4 : if (!torture_close_connection(cli_win)) {
517 0 : correct = false;
518 : }
519 :
520 4 : TALLOC_FREE(frame);
521 4 : return correct;
522 : }
523 :
524 : /*
525 : Test POSIX readlink of symlinks
526 : */
527 4 : bool run_posix_readlink_test(int dummy)
528 : {
529 4 : TALLOC_CTX *frame = NULL;
530 4 : struct cli_state *cli_unix = NULL;
531 4 : uint16_t fnum = (uint16_t)-1;
532 0 : NTSTATUS status;
533 4 : const char *file = "file";
534 4 : const char *symlnk_dangling = "dangling";
535 4 : const char *symlnk_dst_dangling = "xxxxxxx";
536 4 : const char *symlnk_in_share = "symlnk_in_share";
537 4 : const char *symlnk_dst_in_share = file;
538 4 : const char *symlnk_outside_share = "symlnk_outside_share";
539 4 : const char *symlnk_dst_outside_share = "/etc/passwd";
540 4 : struct posix_test_entry entries[] = {
541 : {
542 : .name = symlnk_dangling,
543 : .target = symlnk_dst_dangling,
544 : .expected = symlnk_dangling,
545 : }, {
546 : .name = symlnk_in_share,
547 : .target = symlnk_dst_in_share,
548 : .expected = symlnk_in_share,
549 : }, {
550 : .name = symlnk_outside_share,
551 : .target = symlnk_dst_outside_share,
552 : .expected = symlnk_outside_share,
553 : }, {
554 : .name = NULL,
555 : }
556 : };
557 4 : struct posix_test_state _state = {
558 : .entries = &entries[0],
559 : };
560 4 : struct posix_test_state *state = &_state;
561 0 : int i;
562 4 : bool correct = false;
563 :
564 4 : frame = talloc_stackframe();
565 :
566 4 : printf("Starting POSIX-READLINK test\n");
567 4 : state->flavour = POSIX;
568 :
569 4 : if (!torture_open_connection(&cli_unix, 0)) {
570 0 : TALLOC_FREE(frame);
571 0 : return false;
572 : }
573 :
574 4 : torture_conn_set_sockopt(cli_unix);
575 :
576 4 : status = torture_setup_unix_extensions(cli_unix);
577 4 : if (!NT_STATUS_IS_OK(status)) {
578 0 : TALLOC_FREE(frame);
579 0 : return false;
580 : }
581 :
582 4 : cli_posix_unlink(cli_unix, file);
583 4 : cli_posix_unlink(cli_unix, symlnk_dangling);
584 4 : cli_posix_unlink(cli_unix, symlnk_in_share);
585 4 : cli_posix_unlink(cli_unix, symlnk_outside_share);
586 :
587 4 : status = cli_posix_open(cli_unix,
588 : file,
589 : O_RDWR|O_CREAT,
590 : 0666,
591 : &fnum);
592 4 : if (!NT_STATUS_IS_OK(status)) {
593 0 : printf("cli_posix_open of %s failed error %s\n",
594 : file,
595 : nt_errstr(status));
596 0 : goto out;
597 : }
598 :
599 4 : status = cli_close(cli_unix, fnum);
600 4 : if (!NT_STATUS_IS_OK(status)) {
601 0 : printf("cli_close failed %s\n", nt_errstr(status));
602 0 : goto out;
603 : }
604 4 : fnum = (uint16_t)-1;
605 :
606 16 : for (i = 0; entries[i].name != NULL; i++) {
607 12 : status = cli_posix_symlink(cli_unix,
608 : entries[i].target,
609 : entries[i].name);
610 12 : if (!NT_STATUS_IS_OK(status)) {
611 0 : printf("POSIX symlink of %s failed (%s)\n",
612 : symlnk_dangling, nt_errstr(status));
613 0 : goto out;
614 : }
615 : }
616 :
617 16 : for (i = 0; entries[i].name != NULL; i++) {
618 12 : char *target = NULL;
619 :
620 12 : status = cli_readlink(
621 : cli_unix,
622 : entries[i].name,
623 : talloc_tos(),
624 : &target,
625 : NULL,
626 : NULL);
627 12 : if (!NT_STATUS_IS_OK(status)) {
628 0 : printf("POSIX readlink on %s failed (%s)\n",
629 : entries[i].name, nt_errstr(status));
630 0 : goto out;
631 : }
632 12 : if (strequal(target, entries[i].target)) {
633 12 : entries[i].ok = true;
634 12 : entries[i].returned_size = strlen(target);
635 : }
636 : }
637 :
638 4 : if (!posix_test_entry_check(state,
639 : symlnk_dangling,
640 : true,
641 : strlen(symlnk_dst_dangling)))
642 : {
643 0 : goto out;
644 : }
645 4 : if (!posix_test_entry_check(state,
646 : symlnk_outside_share,
647 : true,
648 : strlen(symlnk_dst_outside_share)))
649 : {
650 0 : goto out;
651 : }
652 4 : if (!posix_test_entry_check(state,
653 : symlnk_in_share,
654 : true,
655 : strlen(symlnk_dst_in_share))) {
656 0 : goto out;
657 : }
658 :
659 4 : printf("POSIX-READLINK test passed\n");
660 4 : correct = true;
661 :
662 4 : out:
663 4 : cli_posix_unlink(cli_unix, file);
664 4 : cli_posix_unlink(cli_unix, symlnk_dangling);
665 4 : cli_posix_unlink(cli_unix, symlnk_in_share);
666 4 : cli_posix_unlink(cli_unix, symlnk_outside_share);
667 :
668 4 : if (!torture_close_connection(cli_unix)) {
669 0 : correct = false;
670 : }
671 :
672 4 : TALLOC_FREE(frame);
673 4 : return correct;
674 : }
675 :
676 : /*
677 : Test POSIX stat of symlinks
678 : */
679 4 : bool run_posix_stat_test(int dummy)
680 : {
681 4 : TALLOC_CTX *frame = NULL;
682 4 : struct cli_state *cli_unix = NULL;
683 4 : uint16_t fnum = (uint16_t)-1;
684 0 : NTSTATUS status;
685 4 : const char *file = "file";
686 4 : const char *symlnk_dangling = "dangling";
687 4 : const char *symlnk_dst_dangling = "xxxxxxx";
688 4 : const char *symlnk_in_share = "symlnk_in_share";
689 4 : const char *symlnk_dst_in_share = file;
690 4 : const char *symlnk_outside_share = "symlnk_outside_share";
691 4 : const char *symlnk_dst_outside_share = "/etc/passwd";
692 4 : struct posix_test_entry entries[] = {
693 : {
694 : .name = symlnk_dangling,
695 : .target = symlnk_dst_dangling,
696 : .expected = symlnk_dangling,
697 : }, {
698 : .name = symlnk_in_share,
699 : .target = symlnk_dst_in_share,
700 : .expected = symlnk_in_share,
701 : }, {
702 : .name = symlnk_outside_share,
703 : .target = symlnk_dst_outside_share,
704 : .expected = symlnk_outside_share,
705 : }, {
706 : .name = NULL,
707 : }
708 : };
709 4 : struct posix_test_state _state = {
710 : .entries = &entries[0],
711 : };
712 4 : struct posix_test_state *state = &_state;
713 0 : int i;
714 4 : bool correct = false;
715 :
716 4 : frame = talloc_stackframe();
717 :
718 4 : printf("Starting POSIX-STAT test\n");
719 4 : state->flavour = POSIX;
720 :
721 4 : if (!torture_open_connection(&cli_unix, 0)) {
722 0 : TALLOC_FREE(frame);
723 0 : return false;
724 : }
725 :
726 4 : torture_conn_set_sockopt(cli_unix);
727 :
728 4 : status = torture_setup_unix_extensions(cli_unix);
729 4 : if (!NT_STATUS_IS_OK(status)) {
730 0 : TALLOC_FREE(frame);
731 0 : return false;
732 : }
733 :
734 4 : cli_posix_unlink(cli_unix, file);
735 4 : cli_posix_unlink(cli_unix, symlnk_dangling);
736 4 : cli_posix_unlink(cli_unix, symlnk_in_share);
737 4 : cli_posix_unlink(cli_unix, symlnk_outside_share);
738 :
739 4 : status = cli_posix_open(cli_unix,
740 : file,
741 : O_RDWR|O_CREAT,
742 : 0666,
743 : &fnum);
744 4 : if (!NT_STATUS_IS_OK(status)) {
745 0 : printf("cli_posix_open of %s failed error %s\n",
746 : file,
747 : nt_errstr(status));
748 0 : goto out;
749 : }
750 :
751 4 : status = cli_close(cli_unix, fnum);
752 4 : if (!NT_STATUS_IS_OK(status)) {
753 0 : printf("cli_close failed %s\n", nt_errstr(status));
754 0 : goto out;
755 : }
756 4 : fnum = (uint16_t)-1;
757 :
758 16 : for (i = 0; entries[i].name != NULL; i++) {
759 12 : status = cli_posix_symlink(cli_unix,
760 : entries[i].target,
761 : entries[i].name);
762 12 : if (!NT_STATUS_IS_OK(status)) {
763 0 : printf("POSIX symlink of %s failed (%s)\n",
764 : symlnk_dangling, nt_errstr(status));
765 0 : goto out;
766 : }
767 : }
768 :
769 16 : for (i = 0; entries[i].name != NULL; i++) {
770 0 : SMB_STRUCT_STAT sbuf;
771 :
772 12 : status = cli_posix_stat(cli_unix,
773 : entries[i].name,
774 : &sbuf);
775 12 : if (!NT_STATUS_IS_OK(status)) {
776 0 : printf("POSIX stat on %s failed (%s)\n",
777 : entries[i].name, nt_errstr(status));
778 0 : continue;
779 : }
780 12 : entries[i].ok = true;
781 12 : entries[i].returned_size = sbuf.st_ex_size;
782 : }
783 :
784 4 : if (!posix_test_entry_check(state,
785 : symlnk_dangling,
786 : true,
787 : strlen(symlnk_dst_dangling)))
788 : {
789 0 : goto out;
790 : }
791 4 : if (!posix_test_entry_check(state,
792 : symlnk_outside_share,
793 : true,
794 : strlen(symlnk_dst_outside_share)))
795 : {
796 0 : goto out;
797 : }
798 4 : if (!posix_test_entry_check(state,
799 : symlnk_in_share,
800 : true,
801 : strlen(symlnk_dst_in_share))) {
802 0 : goto out;
803 : }
804 :
805 4 : printf("POSIX-STAT test passed\n");
806 4 : correct = true;
807 :
808 4 : out:
809 4 : cli_posix_unlink(cli_unix, file);
810 4 : cli_posix_unlink(cli_unix, symlnk_dangling);
811 4 : cli_posix_unlink(cli_unix, symlnk_in_share);
812 4 : cli_posix_unlink(cli_unix, symlnk_outside_share);
813 :
814 4 : if (!torture_close_connection(cli_unix)) {
815 0 : correct = false;
816 : }
817 :
818 4 : TALLOC_FREE(frame);
819 4 : return correct;
820 : }
821 :
822 : /*
823 : Test Creating files and directories directly
824 : under a symlink.
825 : */
826 4 : bool run_posix_symlink_parent_test(int dummy)
827 : {
828 4 : TALLOC_CTX *frame = NULL;
829 4 : struct cli_state *cli_unix = NULL;
830 4 : uint16_t fnum = (uint16_t)-1;
831 0 : NTSTATUS status;
832 4 : const char *parent_dir = "target_dir";
833 4 : const char *parent_symlink = "symlink_to_target_dir";
834 4 : const char *fname_real = "target_dir/file";
835 4 : const char *dname_real = "target_dir/dir";
836 4 : const char *fname_link = "symlink_to_target_dir/file";
837 4 : const char *dname_link = "symlink_to_target_dir/dir";
838 4 : const char *sname_link = "symlink_to_target_dir/symlink";
839 4 : const char *hname_link = "symlink_to_target_dir/hardlink";
840 4 : bool correct = false;
841 :
842 4 : frame = talloc_stackframe();
843 :
844 4 : printf("Starting POSIX-SYMLINK-PARENT test\n");
845 :
846 4 : if (!torture_open_connection(&cli_unix, 0)) {
847 0 : TALLOC_FREE(frame);
848 0 : return false;
849 : }
850 :
851 4 : torture_conn_set_sockopt(cli_unix);
852 :
853 4 : status = torture_setup_unix_extensions(cli_unix);
854 4 : if (!NT_STATUS_IS_OK(status)) {
855 0 : TALLOC_FREE(frame);
856 0 : return false;
857 : }
858 :
859 : /* Start with a clean slate. */
860 4 : cli_posix_unlink(cli_unix, fname_real);
861 4 : cli_posix_rmdir(cli_unix, dname_real);
862 4 : cli_posix_unlink(cli_unix, fname_link);
863 4 : cli_posix_rmdir(cli_unix, dname_link);
864 4 : cli_posix_unlink(cli_unix, sname_link);
865 4 : cli_posix_unlink(cli_unix, hname_link);
866 4 : cli_posix_unlink(cli_unix, parent_symlink);
867 4 : cli_posix_rmdir(cli_unix, parent_dir);
868 :
869 : /* Create parent_dir. */
870 4 : status = cli_posix_mkdir(cli_unix, parent_dir, 0777);
871 4 : if (!NT_STATUS_IS_OK(status)) {
872 0 : printf("cli_posix_mkdir of %s failed error %s\n",
873 : parent_dir,
874 : nt_errstr(status));
875 0 : goto out;
876 : }
877 : /* Create symlink to parent_dir. */
878 4 : status = cli_posix_symlink(cli_unix,
879 : parent_dir,
880 : parent_symlink);
881 4 : if (!NT_STATUS_IS_OK(status)) {
882 0 : printf("cli_posix_symlink of %s -> %s failed error %s\n",
883 : parent_symlink,
884 : parent_dir,
885 : nt_errstr(status));
886 0 : goto out;
887 : }
888 : /* Try and create a directory under the symlink. */
889 4 : status = cli_posix_mkdir(cli_unix, dname_link, 0777);
890 4 : if (!NT_STATUS_IS_OK(status)) {
891 0 : printf("cli_posix_mkdir of %s failed error %s\n",
892 : dname_link,
893 : nt_errstr(status));
894 0 : goto out;
895 : }
896 : /* Try and create a file under the symlink. */
897 4 : status = cli_posix_open(cli_unix,
898 : fname_link,
899 : O_RDWR|O_CREAT,
900 : 0666,
901 : &fnum);
902 4 : if (!NT_STATUS_IS_OK(status)) {
903 0 : printf("cli_posix_open of %s failed error %s\n",
904 : fname_link,
905 : nt_errstr(status));
906 0 : goto out;
907 : }
908 4 : status = cli_close(cli_unix, fnum);
909 4 : if (!NT_STATUS_IS_OK(status)) {
910 0 : printf("cli_close failed %s\n", nt_errstr(status));
911 0 : goto out;
912 : }
913 4 : fnum = (uint16_t)-1;
914 :
915 : /* Try and create a symlink to the file under the symlink. */
916 4 : status = cli_posix_symlink(cli_unix,
917 : fname_link,
918 : sname_link);
919 4 : if (!NT_STATUS_IS_OK(status)) {
920 0 : printf("cli_posix_symlink of %s -> %s failed error %s\n",
921 : sname_link,
922 : fname_link,
923 : nt_errstr(status));
924 0 : goto out;
925 : }
926 :
927 : /* Try and create a hardlink to the file under the symlink. */
928 4 : status = cli_posix_hardlink(cli_unix,
929 : fname_link,
930 : hname_link);
931 4 : if (!NT_STATUS_IS_OK(status)) {
932 0 : printf("cli_posix_hardlink of %s -> %s failed error %s\n",
933 : hname_link,
934 : fname_link,
935 : nt_errstr(status));
936 0 : goto out;
937 : }
938 :
939 : /* Ensure we can delete the symlink via the parent symlink */
940 4 : status = cli_posix_unlink(cli_unix, sname_link);
941 4 : if (!NT_STATUS_IS_OK(status)) {
942 0 : printf("cli_posix_unlink of %s failed error %s\n",
943 : sname_link,
944 : nt_errstr(status));
945 0 : goto out;
946 : }
947 :
948 : /* Ensure we can delete the hardlink via the parent symlink */
949 4 : status = cli_posix_unlink(cli_unix, hname_link);
950 4 : if (!NT_STATUS_IS_OK(status)) {
951 0 : printf("cli_posix_unlink of %s failed error %s\n",
952 : hname_link,
953 : nt_errstr(status));
954 0 : goto out;
955 : }
956 :
957 : /* Ensure we can delete the directory via the parent symlink */
958 4 : status = cli_posix_rmdir(cli_unix, dname_link);
959 4 : if (!NT_STATUS_IS_OK(status)) {
960 0 : printf("cli_posix_rmdir of %s failed error %s\n",
961 : dname_link,
962 : nt_errstr(status));
963 0 : goto out;
964 : }
965 : /* Ensure we can delete the file via the parent symlink */
966 4 : status = cli_posix_unlink(cli_unix, fname_link);
967 4 : if (!NT_STATUS_IS_OK(status)) {
968 0 : printf("cli_posix_unlink of %s failed error %s\n",
969 : fname_link,
970 : nt_errstr(status));
971 0 : goto out;
972 : }
973 :
974 4 : printf("POSIX-SYMLINK-PARENT test passed\n");
975 4 : correct = true;
976 :
977 4 : out:
978 4 : if (fnum != (uint16_t)-1) {
979 0 : cli_close(cli_unix, fnum);
980 : }
981 4 : cli_posix_unlink(cli_unix, fname_real);
982 4 : cli_posix_rmdir(cli_unix, dname_real);
983 4 : cli_posix_unlink(cli_unix, fname_link);
984 4 : cli_posix_rmdir(cli_unix, dname_link);
985 4 : cli_posix_unlink(cli_unix, sname_link);
986 4 : cli_posix_unlink(cli_unix, hname_link);
987 4 : cli_posix_unlink(cli_unix, parent_symlink);
988 4 : cli_posix_rmdir(cli_unix, parent_dir);
989 :
990 4 : if (!torture_close_connection(cli_unix)) {
991 0 : correct = false;
992 : }
993 :
994 4 : TALLOC_FREE(frame);
995 4 : return correct;
996 : }
997 :
998 : /*
999 : Ensure we get an error when doing chmod on a symlink,
1000 : whether it is pointing to a real object or dangling.
1001 : */
1002 4 : bool run_posix_symlink_chmod_test(int dummy)
1003 : {
1004 4 : TALLOC_CTX *frame = NULL;
1005 4 : struct cli_state *cli_unix = NULL;
1006 0 : NTSTATUS status;
1007 4 : uint16_t fnum = (uint16_t)-1;
1008 4 : const char *fname_real = "file_real";
1009 4 : const char *fname_real_symlink = "file_real_symlink";
1010 4 : const char *nonexist = "nonexist";
1011 4 : const char *nonexist_symlink = "dangling_symlink";
1012 4 : bool correct = false;
1013 :
1014 4 : frame = talloc_stackframe();
1015 :
1016 4 : printf("Starting POSIX-SYMLINK-CHMOD test\n");
1017 :
1018 4 : if (!torture_open_connection(&cli_unix, 0)) {
1019 0 : TALLOC_FREE(frame);
1020 0 : return false;
1021 : }
1022 :
1023 4 : torture_conn_set_sockopt(cli_unix);
1024 :
1025 4 : status = torture_setup_unix_extensions(cli_unix);
1026 4 : if (!NT_STATUS_IS_OK(status)) {
1027 0 : TALLOC_FREE(frame);
1028 0 : return false;
1029 : }
1030 :
1031 : /* Start with a clean slate. */
1032 4 : cli_posix_unlink(cli_unix, fname_real);
1033 4 : cli_posix_unlink(cli_unix, fname_real_symlink);
1034 4 : cli_posix_unlink(cli_unix, nonexist);
1035 4 : cli_posix_unlink(cli_unix, nonexist_symlink);
1036 :
1037 : /* Create a real file. */
1038 4 : status = cli_posix_open(cli_unix,
1039 : fname_real,
1040 : O_RDWR|O_CREAT,
1041 : 0644,
1042 : &fnum);
1043 4 : if (!NT_STATUS_IS_OK(status)) {
1044 0 : printf("cli_posix_open of %s failed error %s\n",
1045 : fname_real,
1046 : nt_errstr(status));
1047 0 : goto out;
1048 : }
1049 4 : status = cli_close(cli_unix, fnum);
1050 4 : if (!NT_STATUS_IS_OK(status)) {
1051 0 : printf("cli_close failed %s\n", nt_errstr(status));
1052 0 : goto out;
1053 : }
1054 4 : fnum = (uint16_t)-1;
1055 :
1056 : /* Create symlink to real target. */
1057 4 : status = cli_posix_symlink(cli_unix,
1058 : fname_real,
1059 : fname_real_symlink);
1060 4 : if (!NT_STATUS_IS_OK(status)) {
1061 0 : printf("cli_posix_symlink of %s -> %s failed error %s\n",
1062 : fname_real_symlink,
1063 : fname_real,
1064 : nt_errstr(status));
1065 0 : goto out;
1066 : }
1067 :
1068 : /* We should not be able to chmod symlinks that point to something. */
1069 4 : status = cli_posix_chmod(cli_unix, fname_real_symlink, 0777);
1070 :
1071 : /* This should fail with something other than server crashed. */
1072 4 : if (NT_STATUS_IS_OK(status)) {
1073 0 : printf("cli_posix_chmod of %s succeeded (should have failed)\n",
1074 : fname_real_symlink);
1075 0 : goto out;
1076 : }
1077 4 : if (NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_DISCONNECTED)) {
1078 : /* Oops. Server crashed. */
1079 0 : printf("cli_posix_chmod of %s failed error %s\n",
1080 : fname_real_symlink,
1081 : nt_errstr(status));
1082 0 : goto out;
1083 : }
1084 : /* Any other failure is ok. */
1085 :
1086 : /* Now create symlink to non-existing target. */
1087 4 : status = cli_posix_symlink(cli_unix,
1088 : nonexist,
1089 : nonexist_symlink);
1090 4 : if (!NT_STATUS_IS_OK(status)) {
1091 0 : printf("cli_posix_symlink of %s -> %s failed error %s\n",
1092 : nonexist_symlink,
1093 : nonexist,
1094 : nt_errstr(status));
1095 0 : goto out;
1096 : }
1097 :
1098 : /* We should not be able to chmod symlinks that point to nothing. */
1099 4 : status = cli_posix_chmod(cli_unix, nonexist_symlink, 0777);
1100 :
1101 : /* This should fail with something other than server crashed. */
1102 4 : if (NT_STATUS_IS_OK(status)) {
1103 0 : printf("cli_posix_chmod of %s succeeded (should have failed)\n",
1104 : nonexist_symlink);
1105 0 : goto out;
1106 : }
1107 4 : if (NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_DISCONNECTED)) {
1108 : /* Oops. Server crashed. */
1109 0 : printf("cli_posix_chmod of %s failed error %s\n",
1110 : nonexist_symlink,
1111 : nt_errstr(status));
1112 0 : goto out;
1113 : }
1114 :
1115 : /* Any other failure is ok. */
1116 4 : printf("POSIX-SYMLINK-CHMOD test passed (expected failure was %s)\n",
1117 : nt_errstr(status));
1118 4 : correct = true;
1119 :
1120 4 : out:
1121 4 : if (fnum != (uint16_t)-1) {
1122 0 : cli_close(cli_unix, fnum);
1123 : }
1124 4 : cli_posix_unlink(cli_unix, fname_real);
1125 4 : cli_posix_unlink(cli_unix, fname_real_symlink);
1126 4 : cli_posix_unlink(cli_unix, nonexist);
1127 4 : cli_posix_unlink(cli_unix, nonexist_symlink);
1128 :
1129 4 : if (!torture_close_connection(cli_unix)) {
1130 0 : correct = false;
1131 : }
1132 :
1133 4 : TALLOC_FREE(frame);
1134 4 : return correct;
1135 : }
1136 :
1137 : /*
1138 : Ensure we get an ACL containing OI|IO ACE entries
1139 : after we add a default POSIX ACL to a directory.
1140 : This will only ever be an SMB1 test as it depends
1141 : on POSIX ACL semantics.
1142 : */
1143 4 : bool run_posix_dir_default_acl_test(int dummy)
1144 : {
1145 4 : TALLOC_CTX *frame = NULL;
1146 4 : struct cli_state *cli_unix = NULL;
1147 0 : NTSTATUS status;
1148 4 : uint16_t fnum = (uint16_t)-1;
1149 4 : const char *dname = "dir_with_default_acl";
1150 4 : bool correct = false;
1151 0 : SMB_STRUCT_STAT sbuf;
1152 4 : size_t acl_size = 0;
1153 4 : char *aclbuf = NULL;
1154 4 : size_t num_file_acls = 0;
1155 4 : size_t num_dir_acls = 0;
1156 0 : size_t expected_buflen;
1157 4 : uint8_t def_acl[SMB_POSIX_ACL_HEADER_SIZE +
1158 : 5*SMB_POSIX_ACL_ENTRY_SIZE] = {0};
1159 4 : uint8_t *p = NULL;
1160 4 : uint32_t i = 0;
1161 4 : struct security_descriptor *sd = NULL;
1162 4 : bool got_inherit = false;
1163 :
1164 4 : frame = talloc_stackframe();
1165 :
1166 4 : printf("Starting POSIX-DIR-DEFAULT-ACL test\n");
1167 :
1168 4 : if (!torture_open_connection(&cli_unix, 0)) {
1169 0 : TALLOC_FREE(frame);
1170 0 : return false;
1171 : }
1172 :
1173 4 : torture_conn_set_sockopt(cli_unix);
1174 :
1175 4 : status = torture_setup_unix_extensions(cli_unix);
1176 4 : if (!NT_STATUS_IS_OK(status)) {
1177 0 : TALLOC_FREE(frame);
1178 0 : return false;
1179 : }
1180 :
1181 : /* Start with a clean slate. */
1182 4 : cli_posix_unlink(cli_unix, dname);
1183 4 : cli_posix_rmdir(cli_unix, dname);
1184 :
1185 4 : status = cli_posix_mkdir(cli_unix, dname, 0777);
1186 4 : if (!NT_STATUS_IS_OK(status)) {
1187 0 : printf("cli_posix_mkdir of %s failed error %s\n",
1188 : dname,
1189 : nt_errstr(status));
1190 0 : goto out;
1191 : }
1192 :
1193 : /* Do a posix stat to get the owner. */
1194 4 : status = cli_posix_stat(cli_unix, dname, &sbuf);
1195 4 : if (!NT_STATUS_IS_OK(status)) {
1196 0 : printf("cli_posix_stat of %s failed %s\n",
1197 : dname,
1198 : nt_errstr(status));
1199 0 : goto out;
1200 : }
1201 :
1202 : /* Get the ACL on the directory. */
1203 4 : status = cli_posix_getacl(cli_unix, dname, frame, &acl_size, &aclbuf);
1204 4 : if (!NT_STATUS_IS_OK(status)) {
1205 0 : printf("cli_posix_getacl on %s failed %s\n",
1206 : dname,
1207 : nt_errstr(status));
1208 0 : goto out;
1209 : }
1210 :
1211 4 : if (acl_size < 6 || SVAL(aclbuf,0) != SMB_POSIX_ACL_VERSION) {
1212 0 : printf("%s, unknown POSIX acl version %u.\n",
1213 : dname,
1214 0 : (unsigned int)CVAL(aclbuf,0) );
1215 0 : goto out;
1216 : }
1217 :
1218 4 : num_file_acls = SVAL(aclbuf,2);
1219 4 : num_dir_acls = SVAL(aclbuf,4);
1220 :
1221 : /*
1222 : * No overflow check, num_*_acls comes from a 16-bit value,
1223 : * and we expect expected_buflen (size_t) to be of at least 32
1224 : * bit.
1225 : */
1226 4 : expected_buflen = SMB_POSIX_ACL_HEADER_SIZE +
1227 4 : SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls);
1228 :
1229 4 : if (acl_size != expected_buflen) {
1230 0 : printf("%s, incorrect POSIX acl buffer size "
1231 : "(should be %zu, was %zu).\n",
1232 : dname,
1233 : expected_buflen,
1234 : acl_size);
1235 0 : goto out;
1236 : }
1237 :
1238 4 : if (num_dir_acls != 0) {
1239 0 : printf("%s, POSIX default acl already exists"
1240 : "(should be 0, was %zu).\n",
1241 : dname,
1242 : num_dir_acls);
1243 0 : goto out;
1244 : }
1245 :
1246 : /*
1247 : * Get the Windows ACL on the directory.
1248 : * Make sure there are no inheritable entries.
1249 : */
1250 4 : status = cli_ntcreate(cli_unix,
1251 : dname,
1252 : 0,
1253 : SEC_STD_READ_CONTROL,
1254 : 0,
1255 : FILE_SHARE_READ|
1256 : FILE_SHARE_WRITE|
1257 : FILE_SHARE_DELETE,
1258 : FILE_OPEN,
1259 : FILE_DIRECTORY_FILE,
1260 : 0x0,
1261 : &fnum,
1262 : NULL);
1263 4 : if (!NT_STATUS_IS_OK(status)) {
1264 0 : printf("Failed to open directory %s: %s\n",
1265 : dname,
1266 : nt_errstr(status));
1267 0 : goto out;
1268 : }
1269 :
1270 4 : status = cli_query_security_descriptor(cli_unix,
1271 : fnum,
1272 : SECINFO_DACL,
1273 : frame,
1274 : &sd);
1275 4 : if (!NT_STATUS_IS_OK(status)) {
1276 0 : printf("Failed to get security descriptor on directory %s: %s\n",
1277 : dname,
1278 : nt_errstr(status));
1279 0 : goto out;
1280 : }
1281 :
1282 16 : for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1283 12 : struct security_ace *ace = &sd->dacl->aces[i];
1284 12 : if (ace->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
1285 : SEC_ACE_FLAG_CONTAINER_INHERIT)) {
1286 0 : printf("security descriptor on directory %s already "
1287 : "contains inheritance flags\n",
1288 : dname);
1289 0 : sec_desc_print(NULL, stdout, sd, true);
1290 0 : goto out;
1291 : }
1292 : }
1293 :
1294 4 : TALLOC_FREE(sd);
1295 :
1296 : /* Construct a new default ACL. */
1297 4 : SSVAL(def_acl,0,SMB_POSIX_ACL_VERSION);
1298 4 : SSVAL(def_acl,2,SMB_POSIX_IGNORE_ACE_ENTRIES);
1299 4 : SSVAL(def_acl,4,5); /* num_dir_acls. */
1300 :
1301 4 : p = def_acl + SMB_POSIX_ACL_HEADER_SIZE;
1302 :
1303 : /* USER_OBJ. */
1304 4 : SCVAL(p,0,SMB_POSIX_ACL_USER_OBJ); /* tagtype. */
1305 4 : SCVAL(p,1,SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE);
1306 4 : p += SMB_POSIX_ACL_ENTRY_SIZE;
1307 :
1308 : /* GROUP_OBJ. */
1309 4 : SCVAL(p,0,SMB_POSIX_ACL_GROUP_OBJ); /* tagtype. */
1310 4 : SCVAL(p,1,SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE);
1311 4 : p += SMB_POSIX_ACL_ENTRY_SIZE;
1312 :
1313 : /* OTHER. */
1314 4 : SCVAL(p,0,SMB_POSIX_ACL_OTHER); /* tagtype. */
1315 4 : SCVAL(p,1,SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE);
1316 4 : p += SMB_POSIX_ACL_ENTRY_SIZE;
1317 :
1318 : /* Explicit user. */
1319 4 : SCVAL(p,0,SMB_POSIX_ACL_USER); /* tagtype. */
1320 4 : SCVAL(p,1,SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE);
1321 4 : SIVAL(p,2,sbuf.st_ex_uid);
1322 4 : p += SMB_POSIX_ACL_ENTRY_SIZE;
1323 :
1324 : /* MASK. */
1325 4 : SCVAL(p,0,SMB_POSIX_ACL_MASK); /* tagtype. */
1326 4 : SCVAL(p,1,SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE);
1327 4 : p += SMB_POSIX_ACL_ENTRY_SIZE;
1328 :
1329 : /* Set the POSIX default ACL. */
1330 4 : status = cli_posix_setacl(cli_unix, dname, def_acl, sizeof(def_acl));
1331 4 : if (!NT_STATUS_IS_OK(status)) {
1332 0 : printf("cli_posix_setacl on %s failed %s\n",
1333 : dname,
1334 : nt_errstr(status));
1335 0 : goto out;
1336 : }
1337 :
1338 : /*
1339 : * Get the Windows ACL on the directory again.
1340 : * Now there should be inheritable entries.
1341 : */
1342 :
1343 4 : status = cli_query_security_descriptor(cli_unix,
1344 : fnum,
1345 : SECINFO_DACL,
1346 : frame,
1347 : &sd);
1348 4 : if (!NT_STATUS_IS_OK(status)) {
1349 0 : printf("Failed (2) to get security descriptor "
1350 : "on directory %s: %s\n",
1351 : dname,
1352 : nt_errstr(status));
1353 0 : goto out;
1354 : }
1355 :
1356 4 : for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1357 4 : struct security_ace *ace = &sd->dacl->aces[i];
1358 4 : if (ace->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
1359 : SEC_ACE_FLAG_CONTAINER_INHERIT)) {
1360 4 : got_inherit = true;
1361 4 : break;
1362 : }
1363 : }
1364 :
1365 4 : if (!got_inherit) {
1366 0 : printf("security descriptor on directory %s does not "
1367 : "contain inheritance flags\n",
1368 : dname);
1369 0 : sec_desc_print(NULL, stdout, sd, true);
1370 0 : goto out;
1371 : }
1372 :
1373 4 : cli_close(cli_unix, fnum);
1374 4 : fnum = (uint16_t)-1;
1375 4 : printf("POSIX-DIR-DEFAULT-ACL test passed\n");
1376 4 : correct = true;
1377 :
1378 4 : out:
1379 :
1380 4 : TALLOC_FREE(sd);
1381 :
1382 4 : if (fnum != (uint16_t)-1) {
1383 0 : cli_close(cli_unix, fnum);
1384 : }
1385 4 : cli_posix_unlink(cli_unix, dname);
1386 4 : cli_posix_rmdir(cli_unix, dname);
1387 :
1388 4 : if (!torture_close_connection(cli_unix)) {
1389 0 : correct = false;
1390 : }
1391 :
1392 4 : TALLOC_FREE(frame);
1393 4 : return correct;
1394 : }
1395 :
1396 : /*
1397 : Ensure we can rename a symlink whether it is
1398 : pointing to a real object or dangling.
1399 : */
1400 4 : bool run_posix_symlink_rename_test(int dummy)
1401 : {
1402 4 : TALLOC_CTX *frame = NULL;
1403 4 : struct cli_state *cli_unix = NULL;
1404 0 : NTSTATUS status;
1405 4 : uint16_t fnum = (uint16_t)-1;
1406 4 : const char *fname_real = "file_real";
1407 4 : const char *fname_real_symlink = "file_real_symlink";
1408 4 : const char *fname_real_symlink_newname = "rename_file_real_symlink";
1409 4 : const char *nonexist = "nonexist";
1410 4 : const char *nonexist_symlink = "dangling_symlink";
1411 4 : const char *nonexist_symlink_newname = "dangling_symlink_rename";
1412 4 : bool correct = false;
1413 :
1414 4 : frame = talloc_stackframe();
1415 :
1416 4 : printf("Starting POSIX-SYMLINK-RENAME test\n");
1417 :
1418 4 : if (!torture_open_connection(&cli_unix, 0)) {
1419 0 : TALLOC_FREE(frame);
1420 0 : return false;
1421 : }
1422 :
1423 4 : torture_conn_set_sockopt(cli_unix);
1424 :
1425 4 : status = torture_setup_unix_extensions(cli_unix);
1426 4 : if (!NT_STATUS_IS_OK(status)) {
1427 0 : TALLOC_FREE(frame);
1428 0 : return false;
1429 : }
1430 :
1431 : /* Start with a clean slate. */
1432 4 : cli_posix_unlink(cli_unix, fname_real);
1433 4 : cli_posix_unlink(cli_unix, fname_real_symlink);
1434 4 : cli_posix_unlink(cli_unix, fname_real_symlink_newname);
1435 4 : cli_posix_unlink(cli_unix, nonexist);
1436 4 : cli_posix_unlink(cli_unix, nonexist_symlink);
1437 4 : cli_posix_unlink(cli_unix, nonexist_symlink_newname);
1438 :
1439 : /* Create a real file. */
1440 4 : status = cli_posix_open(cli_unix,
1441 : fname_real,
1442 : O_RDWR|O_CREAT,
1443 : 0644,
1444 : &fnum);
1445 4 : if (!NT_STATUS_IS_OK(status)) {
1446 0 : printf("cli_posix_open of %s failed error %s\n",
1447 : fname_real,
1448 : nt_errstr(status));
1449 0 : goto out;
1450 : }
1451 4 : status = cli_close(cli_unix, fnum);
1452 4 : if (!NT_STATUS_IS_OK(status)) {
1453 0 : printf("cli_close failed %s\n", nt_errstr(status));
1454 0 : goto out;
1455 : }
1456 4 : fnum = (uint16_t)-1;
1457 :
1458 : /* Create symlink to real target. */
1459 4 : status = cli_posix_symlink(cli_unix,
1460 : fname_real,
1461 : fname_real_symlink);
1462 4 : if (!NT_STATUS_IS_OK(status)) {
1463 0 : printf("cli_posix_symlink of %s -> %s failed error %s\n",
1464 : fname_real_symlink,
1465 : fname_real,
1466 : nt_errstr(status));
1467 0 : goto out;
1468 : }
1469 :
1470 : /* Ensure we can rename the symlink to the real file. */
1471 4 : status = cli_rename(cli_unix,
1472 : fname_real_symlink,
1473 : fname_real_symlink_newname,
1474 : false);
1475 4 : if (!NT_STATUS_IS_OK(status)) {
1476 0 : printf("cli_rename of %s -> %s failed %s\n",
1477 : fname_real_symlink,
1478 : fname_real_symlink_newname,
1479 : nt_errstr(status));
1480 0 : goto out;
1481 : }
1482 :
1483 : /* Now create symlink to non-existing target. */
1484 4 : status = cli_posix_symlink(cli_unix,
1485 : nonexist,
1486 : nonexist_symlink);
1487 4 : if (!NT_STATUS_IS_OK(status)) {
1488 0 : printf("cli_posix_symlink of %s -> %s failed error %s\n",
1489 : nonexist_symlink,
1490 : nonexist,
1491 : nt_errstr(status));
1492 0 : goto out;
1493 : }
1494 :
1495 : /* Ensure we can rename the dangling symlink. */
1496 4 : status = cli_rename(cli_unix,
1497 : nonexist_symlink,
1498 : nonexist_symlink_newname,
1499 : false);
1500 4 : if (!NT_STATUS_IS_OK(status)) {
1501 0 : printf("cli_rename of %s -> %s failed %s\n",
1502 : nonexist_symlink,
1503 : nonexist_symlink_newname,
1504 : nt_errstr(status));
1505 0 : goto out;
1506 : }
1507 :
1508 4 : printf("POSIX-SYMLINK-RENAME test passed\n");
1509 4 : correct = true;
1510 :
1511 4 : out:
1512 4 : if (fnum != (uint16_t)-1) {
1513 0 : cli_close(cli_unix, fnum);
1514 : }
1515 4 : cli_posix_unlink(cli_unix, fname_real);
1516 4 : cli_posix_unlink(cli_unix, fname_real_symlink);
1517 4 : cli_posix_unlink(cli_unix, fname_real_symlink_newname);
1518 4 : cli_posix_unlink(cli_unix, nonexist);
1519 4 : cli_posix_unlink(cli_unix, nonexist_symlink);
1520 4 : cli_posix_unlink(cli_unix, nonexist_symlink_newname);
1521 :
1522 4 : if (!torture_close_connection(cli_unix)) {
1523 0 : correct = false;
1524 : }
1525 :
1526 4 : TALLOC_FREE(frame);
1527 4 : return correct;
1528 : }
1529 :
1530 : /* List of info levels to try with a POSIX symlink path. */
1531 :
1532 : static struct {
1533 : uint32_t level;
1534 : const char *name;
1535 : } posix_smb1_qpath_array[] = {
1536 : { SMB_INFO_STANDARD, "SMB_INFO_STANDARD"},
1537 : { SMB_INFO_QUERY_EA_SIZE, "SMB_INFO_QUERY_EA_SIZE"},
1538 : { SMB_INFO_IS_NAME_VALID, "SMB_INFO_IS_NAME_VALID"},
1539 : { SMB_INFO_QUERY_EAS_FROM_LIST, "SMB_INFO_QUERY_EAS_FROM_LIST"},
1540 : { SMB_INFO_QUERY_ALL_EAS, "SMB_INFO_QUERY_ALL_EAS"},
1541 : { SMB_FILE_BASIC_INFORMATION, "SMB_FILE_BASIC_INFORMATION"},
1542 : { SMB_FILE_STANDARD_INFORMATION, "SMB_FILE_STANDARD_INFORMATION"},
1543 : { SMB_FILE_EA_INFORMATION, "SMB_FILE_EA_INFORMATION"},
1544 : { SMB_FILE_ALTERNATE_NAME_INFORMATION,"SMB_FILE_ALTERNATE_NAME_INFORMATION"},
1545 : { SMB_QUERY_FILE_NAME_INFO, "SMB_QUERY_FILE_NAME_INFO"},
1546 : { SMB_FILE_NORMALIZED_NAME_INFORMATION,"SMB_FILE_NORMALIZED_NAME_INFORMATION"},
1547 : { SMB_FILE_ALLOCATION_INFORMATION, "SMB_FILE_ALLOCATION_INFORMATION"},
1548 : { SMB_FILE_END_OF_FILE_INFORMATION, "SMB_FILE_END_OF_FILE_INFORMATION"},
1549 : { SMB_FILE_ALL_INFORMATION, "SMB_FILE_ALL_INFORMATION"},
1550 : { SMB_FILE_INTERNAL_INFORMATION, "SMB_FILE_INTERNAL_INFORMATION"},
1551 : { SMB_FILE_ACCESS_INFORMATION, "SMB_FILE_ACCESS_INFORMATION"},
1552 : { SMB_FILE_NAME_INFORMATION, "SMB_FILE_NAME_INFORMATION"},
1553 : { SMB_FILE_DISPOSITION_INFORMATION, "SMB_FILE_DISPOSITION_INFORMATION"},
1554 : { SMB_FILE_POSITION_INFORMATION, "SMB_FILE_POSITION_INFORMATION"},
1555 : { SMB_FILE_MODE_INFORMATION, "SMB_FILE_MODE_INFORMATION"},
1556 : { SMB_FILE_ALIGNMENT_INFORMATION, "SMB_FILE_ALIGNMENT_INFORMATION"},
1557 : { SMB_FILE_STREAM_INFORMATION, "SMB_FILE_STREAM_INFORMATION"},
1558 : { SMB_FILE_COMPRESSION_INFORMATION, "SMB_FILE_COMPRESSION_INFORMATION"},
1559 : { SMB_FILE_NETWORK_OPEN_INFORMATION, "SMB_FILE_NETWORK_OPEN_INFORMATION"},
1560 : { SMB_FILE_ATTRIBUTE_TAG_INFORMATION, "SMB_FILE_ATTRIBUTE_TAG_INFORMATION"},
1561 : { SMB_QUERY_FILE_UNIX_BASIC, "SMB_QUERY_FILE_UNIX_BASIC"},
1562 : { SMB_QUERY_FILE_UNIX_INFO2, "SMB_QUERY_FILE_UNIX_INFO2"},
1563 : { SMB_QUERY_FILE_UNIX_LINK, "SMB_QUERY_FILE_UNIX_LINK"},
1564 : { SMB_QUERY_POSIX_ACL, "SMB_QUERY_POSIX_ACL"},
1565 : { SMB_QUERY_POSIX_LOCK, "SMB_QUERY_POSIX_LOCK"},
1566 : };
1567 :
1568 240 : static NTSTATUS do_qpath(TALLOC_CTX *ctx,
1569 : struct cli_state *cli_unix,
1570 : const char *fname,
1571 : size_t i)
1572 : {
1573 0 : NTSTATUS status;
1574 :
1575 240 : if (posix_smb1_qpath_array[i].level ==
1576 : SMB_INFO_QUERY_EAS_FROM_LIST) {
1577 0 : uint16_t setup;
1578 0 : uint8_t *param;
1579 0 : uint8_t data[8];
1580 8 : uint8_t *rparam = NULL;
1581 8 : uint8_t *rdata = NULL;
1582 8 : uint32_t rbytes = 0;
1583 :
1584 : /* Set up an EA list with 'a' as the single name. */
1585 8 : SIVAL(data,0, 8);
1586 8 : SCVAL(data,4, 2); /* namelen. */
1587 8 : SCVAL(data,5, 'a');
1588 8 : SCVAL(data,6, '\0'); /* name. */
1589 8 : SCVAL(data,7, '\0'); /* padding. */
1590 :
1591 8 : SSVAL(&setup, 0, TRANSACT2_QPATHINFO);
1592 :
1593 8 : param = talloc_zero_array(ctx, uint8_t, 6);
1594 8 : if (param == NULL) {
1595 0 : return NT_STATUS_NO_MEMORY;
1596 : }
1597 8 : SSVAL(param, 0, SMB_INFO_QUERY_EAS_FROM_LIST);
1598 8 : param = trans2_bytes_push_str(param,
1599 8 : smbXcli_conn_use_unicode(cli_unix->conn),
1600 : fname,
1601 8 : strlen(fname)+1,
1602 : NULL);
1603 8 : if (param == NULL) {
1604 0 : return NT_STATUS_NO_MEMORY;
1605 : }
1606 :
1607 8 : status = cli_trans(ctx,
1608 : cli_unix,
1609 : SMBtrans2,
1610 : NULL,
1611 : -1,
1612 : 0,
1613 : 0,
1614 : &setup, 1, 0,
1615 8 : param, talloc_get_size(param), talloc_get_size(param),
1616 : data, 8, 0,
1617 : NULL,
1618 : NULL, 0, NULL,
1619 : &rparam, 0, &rbytes,
1620 : &rdata, 0, &rbytes);
1621 8 : TALLOC_FREE(rparam);
1622 8 : TALLOC_FREE(rdata);
1623 : } else {
1624 232 : uint8_t *rdata = NULL;
1625 232 : uint32_t num_rdata = 0;
1626 :
1627 232 : status = cli_qpathinfo(ctx,
1628 : cli_unix,
1629 : fname,
1630 232 : posix_smb1_qpath_array[i].level,
1631 : 0, /* min_rdata */
1632 : 65534, /* max_rdata */
1633 : &rdata,
1634 : &num_rdata);
1635 232 : TALLOC_FREE(rdata);
1636 : }
1637 : /*
1638 : * We don't care what came back, so long as the
1639 : * server didn't crash.
1640 : */
1641 240 : if (NT_STATUS_EQUAL(status,
1642 : NT_STATUS_CONNECTION_DISCONNECTED)) {
1643 0 : printf("cli_qpathinfo of %s failed error "
1644 : "NT_STATUS_CONNECTION_DISCONNECTED\n",
1645 : fname);
1646 0 : return status;
1647 : }
1648 :
1649 240 : printf("cli_qpathinfo info %x (%s) of %s got %s "
1650 : "(this is not an error)\n",
1651 240 : (unsigned int)posix_smb1_qpath_array[i].level,
1652 : posix_smb1_qpath_array[i].name,
1653 : fname,
1654 : nt_errstr(status));
1655 :
1656 240 : return NT_STATUS_OK;
1657 : }
1658 :
1659 : /*
1660 : Ensure we can call SMB1 getpathinfo in a symlink,
1661 : pointing to a real object or dangling. We mostly
1662 : expect errors, but the server must not crash.
1663 : */
1664 4 : bool run_posix_symlink_getpathinfo_test(int dummy)
1665 : {
1666 4 : TALLOC_CTX *frame = NULL;
1667 4 : struct cli_state *cli_unix = NULL;
1668 0 : NTSTATUS status;
1669 4 : uint16_t fnum = (uint16_t)-1;
1670 4 : const char *fname_real = "file_getpath_real";
1671 4 : const char *fname_real_symlink = "file_real_getpath_symlink";
1672 4 : const char *nonexist = "nonexist_getpath";
1673 4 : const char *nonexist_symlink = "dangling_getpath_symlink";
1674 4 : bool correct = false;
1675 0 : size_t i;
1676 :
1677 4 : frame = talloc_stackframe();
1678 :
1679 4 : printf("Starting POSIX-SYMLINK-GETPATHINFO test\n");
1680 :
1681 4 : if (!torture_open_connection(&cli_unix, 0)) {
1682 0 : TALLOC_FREE(frame);
1683 0 : return false;
1684 : }
1685 :
1686 4 : torture_conn_set_sockopt(cli_unix);
1687 :
1688 4 : status = torture_setup_unix_extensions(cli_unix);
1689 4 : if (!NT_STATUS_IS_OK(status)) {
1690 0 : TALLOC_FREE(frame);
1691 0 : return false;
1692 : }
1693 :
1694 : /* Start with a clean slate. */
1695 4 : cli_posix_unlink(cli_unix, fname_real);
1696 4 : cli_posix_unlink(cli_unix, fname_real_symlink);
1697 4 : cli_posix_unlink(cli_unix, nonexist);
1698 4 : cli_posix_unlink(cli_unix, nonexist_symlink);
1699 :
1700 : /* Create a real file. */
1701 4 : status = cli_posix_open(cli_unix,
1702 : fname_real,
1703 : O_RDWR|O_CREAT,
1704 : 0644,
1705 : &fnum);
1706 4 : if (!NT_STATUS_IS_OK(status)) {
1707 0 : printf("cli_posix_open of %s failed error %s\n",
1708 : fname_real,
1709 : nt_errstr(status));
1710 0 : goto out;
1711 : }
1712 4 : status = cli_close(cli_unix, fnum);
1713 4 : if (!NT_STATUS_IS_OK(status)) {
1714 0 : printf("cli_close failed %s\n", nt_errstr(status));
1715 0 : goto out;
1716 : }
1717 4 : fnum = (uint16_t)-1;
1718 :
1719 : /* Create symlink to real target. */
1720 4 : status = cli_posix_symlink(cli_unix,
1721 : fname_real,
1722 : fname_real_symlink);
1723 4 : if (!NT_STATUS_IS_OK(status)) {
1724 0 : printf("cli_posix_symlink of %s -> %s failed error %s\n",
1725 : fname_real_symlink,
1726 : fname_real,
1727 : nt_errstr(status));
1728 0 : goto out;
1729 : }
1730 :
1731 : /* Now create symlink to non-existing target. */
1732 4 : status = cli_posix_symlink(cli_unix,
1733 : nonexist,
1734 : nonexist_symlink);
1735 4 : if (!NT_STATUS_IS_OK(status)) {
1736 0 : printf("cli_posix_symlink of %s -> %s failed error %s\n",
1737 : nonexist_symlink,
1738 : nonexist,
1739 : nt_errstr(status));
1740 0 : goto out;
1741 : }
1742 :
1743 124 : for (i = 0; i < ARRAY_SIZE(posix_smb1_qpath_array); i++) {
1744 120 : status = do_qpath(frame,
1745 : cli_unix,
1746 : fname_real_symlink,
1747 : i);
1748 120 : if (!NT_STATUS_IS_OK(status)) {
1749 0 : goto out;
1750 : }
1751 120 : status = do_qpath(frame,
1752 : cli_unix,
1753 : nonexist_symlink,
1754 : i);
1755 120 : if (!NT_STATUS_IS_OK(status)) {
1756 0 : goto out;
1757 : }
1758 : }
1759 :
1760 4 : printf("POSIX-SYMLINK-GETPATHINFO test passed\n");
1761 4 : correct = true;
1762 :
1763 4 : out:
1764 4 : if (fnum != (uint16_t)-1) {
1765 0 : cli_close(cli_unix, fnum);
1766 : }
1767 4 : cli_posix_unlink(cli_unix, fname_real);
1768 4 : cli_posix_unlink(cli_unix, fname_real_symlink);
1769 4 : cli_posix_unlink(cli_unix, nonexist);
1770 4 : cli_posix_unlink(cli_unix, nonexist_symlink);
1771 :
1772 4 : if (!torture_close_connection(cli_unix)) {
1773 0 : correct = false;
1774 : }
1775 :
1776 4 : TALLOC_FREE(frame);
1777 4 : return correct;
1778 : }
1779 :
1780 : /* List of info levels to try with a POSIX symlink path. */
1781 :
1782 : static struct {
1783 : uint32_t level;
1784 : const char *name;
1785 : uint32_t data_len;
1786 : } posix_smb1_setpath_array[] = {
1787 : { SMB_SET_FILE_UNIX_BASIC, "SMB_SET_FILE_UNIX_BASIC", 100},
1788 : { SMB_SET_FILE_UNIX_INFO2, "SMB_SET_FILE_UNIX_INFO2", 116},
1789 : { SMB_SET_FILE_UNIX_LINK, "SMB_SET_FILE_UNIX_LINK", 8},
1790 : { SMB_SET_FILE_UNIX_HLINK, "SMB_SET_FILE_UNIX_HLINK", 8},
1791 : { SMB_SET_POSIX_ACL, "SMB_SET_POSIX_ACL", 6},
1792 : { SMB_SET_POSIX_LOCK, "SMB_SET_POSIX_LOCK", 24},
1793 : { SMB_INFO_STANDARD, "SMB_INFO_STANDARD", 12},
1794 : { SMB_INFO_SET_EA, "SMB_INFO_SET_EA", 10},
1795 : { SMB_FILE_BASIC_INFORMATION, "SMB_FILE_BASIC_INFORMATION", 36},
1796 : { SMB_SET_FILE_ALLOCATION_INFO, "SMB_SET_FILE_ALLOCATION_INFO", 8},
1797 : { SMB_SET_FILE_END_OF_FILE_INFO,"SMB_SET_FILE_END_OF_FILE_INFO",8},
1798 : { SMB_SET_FILE_DISPOSITION_INFO,"SMB_SET_FILE_DISPOSITION_INFO",1},
1799 : { SMB_FILE_POSITION_INFORMATION,"SMB_FILE_POSITION_INFORMATION",8},
1800 : { SMB_FILE_FULL_EA_INFORMATION, "SMB_FILE_FULL_EA_INFORMATION",10},
1801 : { SMB_FILE_MODE_INFORMATION, "SMB_FILE_MODE_INFORMATION", 4},
1802 : { SMB_FILE_SHORT_NAME_INFORMATION,"SMB_FILE_SHORT_NAME_INFORMATION",12},
1803 : { SMB_FILE_RENAME_INFORMATION,"SMB_FILE_RENAME_INFORMATION", 20},
1804 : { SMB_FILE_LINK_INFORMATION, "SMB_FILE_LINK_INFORMATION", 20},
1805 : };
1806 :
1807 144 : static NTSTATUS do_setpath(TALLOC_CTX *ctx,
1808 : struct cli_state *cli_unix,
1809 : const char *fname,
1810 : size_t i)
1811 : {
1812 0 : NTSTATUS status;
1813 144 : uint8_t *data = NULL;
1814 :
1815 144 : data = talloc_zero_array(ctx,
1816 : uint8_t,
1817 : posix_smb1_setpath_array[i].data_len);
1818 144 : if (data == NULL) {
1819 0 : return NT_STATUS_NO_MEMORY;
1820 : }
1821 :
1822 144 : status = cli_setpathinfo(cli_unix,
1823 144 : posix_smb1_setpath_array[i].level,
1824 : fname,
1825 : data,
1826 144 : posix_smb1_setpath_array[i].data_len);
1827 144 : TALLOC_FREE(data);
1828 :
1829 : /*
1830 : * We don't care what came back, so long as the
1831 : * server didn't crash.
1832 : */
1833 144 : if (NT_STATUS_EQUAL(status,
1834 : NT_STATUS_CONNECTION_DISCONNECTED)) {
1835 0 : printf("cli_setpathinfo info %x (%s) of %s failed"
1836 : "error NT_STATUS_CONNECTION_DISCONNECTED\n",
1837 0 : (unsigned int)posix_smb1_setpath_array[i].level,
1838 : posix_smb1_setpath_array[i].name,
1839 : fname);
1840 0 : return status;
1841 : }
1842 :
1843 144 : printf("cli_setpathinfo info %x (%s) of %s got %s "
1844 : "(this is not an error)\n",
1845 144 : (unsigned int)posix_smb1_setpath_array[i].level,
1846 : posix_smb1_setpath_array[i].name,
1847 : fname,
1848 : nt_errstr(status));
1849 :
1850 144 : return NT_STATUS_OK;
1851 : }
1852 :
1853 : /*
1854 : Ensure we can call SMB1 setpathinfo in a symlink,
1855 : pointing to a real object or dangling. We mostly
1856 : expect errors, but the server must not crash.
1857 : */
1858 4 : bool run_posix_symlink_setpathinfo_test(int dummy)
1859 : {
1860 4 : TALLOC_CTX *frame = NULL;
1861 4 : struct cli_state *cli_unix = NULL;
1862 0 : NTSTATUS status;
1863 4 : uint16_t fnum = (uint16_t)-1;
1864 4 : const char *fname_real = "file_setpath_real";
1865 4 : const char *fname_real_symlink = "file_real_setpath_symlink";
1866 4 : const char *nonexist = "nonexist_setpath";
1867 4 : const char *nonexist_symlink = "dangling_setpath_symlink";
1868 4 : bool correct = false;
1869 0 : size_t i;
1870 :
1871 4 : frame = talloc_stackframe();
1872 :
1873 4 : printf("Starting POSIX-SYMLINK-SETPATHINFO test\n");
1874 :
1875 4 : if (!torture_open_connection(&cli_unix, 0)) {
1876 0 : TALLOC_FREE(frame);
1877 0 : return false;
1878 : }
1879 :
1880 4 : torture_conn_set_sockopt(cli_unix);
1881 :
1882 4 : status = torture_setup_unix_extensions(cli_unix);
1883 4 : if (!NT_STATUS_IS_OK(status)) {
1884 0 : TALLOC_FREE(frame);
1885 0 : return false;
1886 : }
1887 :
1888 : /* Start with a clean slate. */
1889 4 : cli_posix_unlink(cli_unix, fname_real);
1890 4 : cli_posix_unlink(cli_unix, fname_real_symlink);
1891 4 : cli_posix_unlink(cli_unix, nonexist);
1892 4 : cli_posix_unlink(cli_unix, nonexist_symlink);
1893 :
1894 : /* Create a real file. */
1895 4 : status = cli_posix_open(cli_unix,
1896 : fname_real,
1897 : O_RDWR|O_CREAT,
1898 : 0644,
1899 : &fnum);
1900 4 : if (!NT_STATUS_IS_OK(status)) {
1901 0 : printf("cli_posix_open of %s failed error %s\n",
1902 : fname_real,
1903 : nt_errstr(status));
1904 0 : goto out;
1905 : }
1906 4 : status = cli_close(cli_unix, fnum);
1907 4 : if (!NT_STATUS_IS_OK(status)) {
1908 0 : printf("cli_close failed %s\n", nt_errstr(status));
1909 0 : goto out;
1910 : }
1911 4 : fnum = (uint16_t)-1;
1912 :
1913 : /* Create symlink to real target. */
1914 4 : status = cli_posix_symlink(cli_unix,
1915 : fname_real,
1916 : fname_real_symlink);
1917 4 : if (!NT_STATUS_IS_OK(status)) {
1918 0 : printf("cli_posix_symlink of %s -> %s failed error %s\n",
1919 : fname_real_symlink,
1920 : fname_real,
1921 : nt_errstr(status));
1922 0 : goto out;
1923 : }
1924 :
1925 : /* Now create symlink to non-existing target. */
1926 4 : status = cli_posix_symlink(cli_unix,
1927 : nonexist,
1928 : nonexist_symlink);
1929 4 : if (!NT_STATUS_IS_OK(status)) {
1930 0 : printf("cli_posix_symlink of %s -> %s failed error %s\n",
1931 : nonexist_symlink,
1932 : nonexist,
1933 : nt_errstr(status));
1934 0 : goto out;
1935 : }
1936 :
1937 76 : for (i = 0; i < ARRAY_SIZE(posix_smb1_setpath_array); i++) {
1938 72 : status = do_setpath(frame,
1939 : cli_unix,
1940 : fname_real_symlink,
1941 : i);
1942 72 : if (!NT_STATUS_IS_OK(status)) {
1943 0 : goto out;
1944 : }
1945 72 : status = do_setpath(frame,
1946 : cli_unix,
1947 : nonexist_symlink,
1948 : i);
1949 72 : if (!NT_STATUS_IS_OK(status)) {
1950 0 : goto out;
1951 : }
1952 : }
1953 :
1954 4 : printf("POSIX-SYMLINK-SETPATHINFO test passed\n");
1955 4 : correct = true;
1956 :
1957 4 : out:
1958 4 : if (fnum != (uint16_t)-1) {
1959 0 : cli_close(cli_unix, fnum);
1960 : }
1961 4 : cli_posix_unlink(cli_unix, fname_real);
1962 4 : cli_posix_unlink(cli_unix, fname_real_symlink);
1963 4 : cli_posix_unlink(cli_unix, nonexist);
1964 4 : cli_posix_unlink(cli_unix, nonexist_symlink);
1965 :
1966 4 : if (!torture_close_connection(cli_unix)) {
1967 0 : correct = false;
1968 : }
1969 :
1970 4 : TALLOC_FREE(frame);
1971 4 : return correct;
1972 : }
|