s3:rpc_server: Fix code spelling
[Samba.git] / source3 / torture / test_posix.c
blobca403360153cad1b751833a1157742b1076c97c8
1 /*
2 Unix SMB/CIFS implementation.
3 Copyright (C) Ralph Boehme 2020
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.
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.
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/>.
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"
29 extern struct cli_credentials *torture_creds;
30 extern fstring host, workgroup, share, password, username, myname;
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;
42 enum client_flavour { WINDOWS, POSIX };
44 struct posix_test_state {
45 enum client_flavour flavour;
46 struct posix_test_entry *entries;
49 static NTSTATUS posix_ls_fn(struct file_info *finfo,
50 const char *name,
51 void *_state)
53 struct posix_test_state *state =
54 (struct posix_test_state *)_state;
55 struct posix_test_entry *e = state->entries;
57 for (; e->name != NULL; e++) {
58 uint32_t attr;
59 if (!strequal(finfo->name, e->expected)) {
60 continue;
62 if (state->flavour == WINDOWS) {
63 attr = e->attr_win;
64 } else {
65 attr = e->attr_lin;
67 if (attr != finfo->attr) {
68 break;
70 e->ok = true;
71 e->returned_size = finfo->size;
72 break;
75 return NT_STATUS_OK;
78 static void posix_test_entries_reset(struct posix_test_state *state)
80 struct posix_test_entry *e = state->entries;
82 for (; e->name != NULL; e++) {
83 e->ok = false;
84 e->returned_size = 0;
88 static bool posix_test_entry_check(struct posix_test_state *state,
89 const char *name,
90 bool expected,
91 uint64_t expected_size)
93 struct posix_test_entry *e = state->entries;
94 bool result = false;
96 for (; e->name != NULL; e++) {
97 if (strequal(name, e->name)) {
98 result = e->ok;
99 break;
102 if (e->name == NULL) {
103 printf("test failed, unknown name: %s\n", name);
104 return false;
107 if (expected == result) {
108 return true;
111 printf("test failed, %s: %s\n",
112 expected ? "missing" : "unexpected",
113 name);
115 return false;
119 Test non-POSIX vs POSIX ls * of symlinks
121 bool run_posix_ls_wildcard_test(int dummy)
123 TALLOC_CTX *frame = NULL;
124 struct cli_state *cli_unix = NULL;
125 struct cli_state *cli_win = NULL;
126 uint16_t fnum = (uint16_t)-1;
127 NTSTATUS status;
128 const char *file = "file";
129 const char *symlnk_dangling = "dangling";
130 const char *symlnk_dst_dangling = "xxxxxxx";
131 const char *symlnk_in_share = "symlnk_in_share";
132 const char *symlnk_dst_in_share = file;
133 const char *symlnk_outside_share = "symlnk_outside_share";
134 const char *symlnk_dst_outside_share = "/etc/passwd";
135 struct posix_test_entry entries[] = {
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,
164 struct posix_test_state _state = {
165 .entries = entries,
167 struct posix_test_state *state = &_state;
168 int i;
169 bool correct = false;
171 frame = talloc_stackframe();
173 printf("Starting POSIX-LS-WILDCARD test\n");
175 if (!torture_open_connection(&cli_unix, 0)) {
176 TALLOC_FREE(frame);
177 return false;
180 if (!torture_open_connection(&cli_win, 0)) {
181 TALLOC_FREE(frame);
182 return false;
185 torture_conn_set_sockopt(cli_unix);
186 torture_conn_set_sockopt(cli_win);
188 status = torture_setup_unix_extensions(cli_unix);
189 if (!NT_STATUS_IS_OK(status)) {
190 TALLOC_FREE(frame);
191 return false;
194 cli_posix_unlink(cli_unix, file);
195 cli_posix_unlink(cli_unix, symlnk_dangling);
196 cli_posix_unlink(cli_unix, symlnk_in_share);
197 cli_posix_unlink(cli_unix, symlnk_outside_share);
199 status = cli_posix_open(cli_unix,
200 file,
201 O_RDWR|O_CREAT,
202 0666,
203 &fnum);
204 if (!NT_STATUS_IS_OK(status)) {
205 printf("cli_posix_open of %s failed error %s\n",
206 file,
207 nt_errstr(status));
208 goto out;
211 status = cli_close(cli_unix, fnum);
212 if (!NT_STATUS_IS_OK(status)) {
213 printf("cli_close failed %s\n", nt_errstr(status));
214 goto out;
216 fnum = (uint16_t)-1;
218 for (i = 0; entries[i].name != NULL; i++) {
219 if (entries[i].target == NULL) {
220 continue;
222 status = cli_posix_symlink(cli_unix,
223 entries[i].target,
224 entries[i].name);
225 if (!NT_STATUS_IS_OK(status)) {
226 printf("POSIX symlink of %s failed (%s)\n",
227 symlnk_dangling, nt_errstr(status));
228 goto out;
232 printf("Doing Windows ls *\n");
233 state->flavour = WINDOWS;
235 status = cli_list(cli_win, "*", 0, posix_ls_fn, state);
236 if (!NT_STATUS_IS_OK(status)) {
237 printf("cli_list failed %s\n", nt_errstr(status));
238 goto out;
241 if (!posix_test_entry_check(state, file, true, 0)) {
242 goto out;
244 if (!posix_test_entry_check(state, symlnk_dangling, false, 0)) {
245 goto out;
247 if (!posix_test_entry_check(state, symlnk_outside_share, false, 0)) {
248 goto out;
250 if (!posix_test_entry_check(state, symlnk_in_share, true, 0)) {
251 goto out;
254 posix_test_entries_reset(state);
256 printf("Doing POSIX ls *\n");
257 state->flavour = POSIX;
259 status = cli_list(cli_unix, "*", 0, posix_ls_fn, state);
260 if (!NT_STATUS_IS_OK(status)) {
261 printf("cli_close failed %s\n", nt_errstr(status));
262 goto out;
265 if (!posix_test_entry_check(state, file, true, 0)) {
266 goto out;
268 if (!posix_test_entry_check(state,
269 symlnk_dangling,
270 true,
271 strlen(symlnk_dst_dangling)))
273 goto out;
275 if (!posix_test_entry_check(state,
276 symlnk_outside_share,
277 true,
278 strlen(symlnk_dst_outside_share)))
280 goto out;
282 if (!posix_test_entry_check(state,
283 symlnk_in_share,
284 true,
285 strlen(symlnk_dst_in_share))) {
286 goto out;
289 printf("POSIX-LS-WILDCARD test passed\n");
290 correct = true;
292 out:
293 cli_posix_unlink(cli_unix, file);
294 cli_posix_unlink(cli_unix, symlnk_dangling);
295 cli_posix_unlink(cli_unix, symlnk_in_share);
296 cli_posix_unlink(cli_unix, symlnk_outside_share);
298 if (!torture_close_connection(cli_unix)) {
299 correct = false;
301 if (!torture_close_connection(cli_win)) {
302 correct = false;
305 TALLOC_FREE(frame);
306 return correct;
310 Test non-POSIX vs POSIX ls single of symlinks
312 bool run_posix_ls_single_test(int dummy)
314 TALLOC_CTX *frame = NULL;
315 struct cli_state *cli_unix = NULL;
316 struct cli_state *cli_win = NULL;
317 uint16_t fnum = (uint16_t)-1;
318 NTSTATUS status;
319 const char *file = "file";
320 const char *symlnk_dangling = "dangling";
321 const char *symlnk_dst_dangling = "xxxxxxx";
322 const char *symlnk_in_share = "symlnk_in_share";
323 const char *symlnk_dst_in_share = file;
324 const char *symlnk_outside_share = "symlnk_outside_share";
325 const char *symlnk_dst_outside_share = "/etc/passwd";
326 struct posix_test_entry entries[] = {
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,
355 struct posix_test_state _state = {
356 .entries = &entries[0],
358 struct posix_test_state *state = &_state;
359 int i;
360 bool correct = false;
362 frame = talloc_stackframe();
364 printf("Starting POSIX-LS-SINGLE test\n");
366 if (!torture_open_connection(&cli_unix, 0)) {
367 TALLOC_FREE(frame);
368 return false;
371 if (!torture_init_connection(&cli_win)) {
372 TALLOC_FREE(frame);
373 return false;
376 status = smbXcli_negprot(cli_win->conn,
377 cli_win->timeout,
378 lp_client_min_protocol(),
379 lp_client_max_protocol(),
380 NULL,
381 NULL,
382 NULL);
383 if (!NT_STATUS_IS_OK(status)) {
384 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
385 TALLOC_FREE(frame);
386 return false;
389 status = cli_session_setup_creds(cli_win, torture_creds);
390 if (!NT_STATUS_IS_OK(status)) {
391 printf("smb2cli_sesssetup returned %s\n", nt_errstr(status));
392 TALLOC_FREE(frame);
393 return false;
396 status = cli_tree_connect(cli_win, share, "?????", NULL);
397 if (!NT_STATUS_IS_OK(status)) {
398 printf("cli_tree_connect returned %s\n", nt_errstr(status));
399 TALLOC_FREE(frame);
400 return false;
402 torture_conn_set_sockopt(cli_unix);
403 torture_conn_set_sockopt(cli_win);
405 status = torture_setup_unix_extensions(cli_unix);
406 if (!NT_STATUS_IS_OK(status)) {
407 TALLOC_FREE(frame);
408 return false;
411 cli_posix_unlink(cli_unix, file);
412 cli_posix_unlink(cli_unix, symlnk_dangling);
413 cli_posix_unlink(cli_unix, symlnk_in_share);
414 cli_posix_unlink(cli_unix, symlnk_outside_share);
416 status = cli_posix_open(cli_unix,
417 file,
418 O_RDWR|O_CREAT,
419 0666,
420 &fnum);
421 if (!NT_STATUS_IS_OK(status)) {
422 printf("cli_posix_open of %s failed error %s\n",
423 file,
424 nt_errstr(status));
425 goto out;
428 status = cli_close(cli_unix, fnum);
429 if (!NT_STATUS_IS_OK(status)) {
430 printf("cli_close failed %s\n", nt_errstr(status));
431 goto out;
433 fnum = (uint16_t)-1;
435 for (i = 0; entries[i].name != NULL; i++) {
436 if (entries[i].target == NULL) {
437 continue;
439 status = cli_posix_symlink(cli_unix,
440 entries[i].target,
441 entries[i].name);
442 if (!NT_STATUS_IS_OK(status)) {
443 printf("POSIX symlink of %s failed (%s)\n",
444 symlnk_dangling, nt_errstr(status));
445 goto out;
449 printf("Doing Windows ls single\n");
450 state->flavour = WINDOWS;
452 cli_list(cli_win, file, 0, posix_ls_fn, state);
453 cli_list(cli_win, symlnk_dangling, 0, posix_ls_fn, state);
454 cli_list(cli_win, symlnk_outside_share, 0, posix_ls_fn, state);
455 cli_list(cli_win, symlnk_in_share, 0, posix_ls_fn, state);
457 if (!posix_test_entry_check(state, file, true, 0)) {
458 goto out;
460 if (!posix_test_entry_check(state, symlnk_dangling, false, 0)) {
461 goto out;
463 if (!posix_test_entry_check(state, symlnk_outside_share, false, 0)) {
464 goto out;
466 if (!posix_test_entry_check(state, symlnk_in_share, true, 0)) {
467 goto out;
470 posix_test_entries_reset(state);
472 printf("Doing POSIX ls single\n");
473 state->flavour = POSIX;
475 cli_list(cli_unix, file, 0, posix_ls_fn, state);
476 cli_list(cli_unix, symlnk_dangling, 0, posix_ls_fn, state);
477 cli_list(cli_unix, symlnk_outside_share, 0, posix_ls_fn, state);
478 cli_list(cli_unix, symlnk_in_share, 0, posix_ls_fn, state);
480 if (!posix_test_entry_check(state, file, true, 0)) {
481 goto out;
483 if (!posix_test_entry_check(state,
484 symlnk_dangling,
485 true,
486 strlen(symlnk_dst_dangling)))
488 goto out;
490 if (!posix_test_entry_check(state,
491 symlnk_outside_share,
492 true,
493 strlen(symlnk_dst_outside_share)))
495 goto out;
497 if (!posix_test_entry_check(state,
498 symlnk_in_share,
499 true,
500 strlen(symlnk_dst_in_share))) {
501 goto out;
504 printf("POSIX-LS-SINGLE test passed\n");
505 correct = true;
507 out:
508 cli_posix_unlink(cli_unix, file);
509 cli_posix_unlink(cli_unix, symlnk_dangling);
510 cli_posix_unlink(cli_unix, symlnk_in_share);
511 cli_posix_unlink(cli_unix, symlnk_outside_share);
513 if (!torture_close_connection(cli_unix)) {
514 correct = false;
516 if (!torture_close_connection(cli_win)) {
517 correct = false;
520 TALLOC_FREE(frame);
521 return correct;
525 Test POSIX readlink of symlinks
527 bool run_posix_readlink_test(int dummy)
529 TALLOC_CTX *frame = NULL;
530 struct cli_state *cli_unix = NULL;
531 uint16_t fnum = (uint16_t)-1;
532 NTSTATUS status;
533 const char *file = "file";
534 const char *symlnk_dangling = "dangling";
535 const char *symlnk_dst_dangling = "xxxxxxx";
536 const char *symlnk_in_share = "symlnk_in_share";
537 const char *symlnk_dst_in_share = file;
538 const char *symlnk_outside_share = "symlnk_outside_share";
539 const char *symlnk_dst_outside_share = "/etc/passwd";
540 struct posix_test_entry entries[] = {
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,
557 struct posix_test_state _state = {
558 .entries = &entries[0],
560 struct posix_test_state *state = &_state;
561 int i;
562 bool correct = false;
564 frame = talloc_stackframe();
566 printf("Starting POSIX-READLINK test\n");
567 state->flavour = POSIX;
569 if (!torture_open_connection(&cli_unix, 0)) {
570 TALLOC_FREE(frame);
571 return false;
574 torture_conn_set_sockopt(cli_unix);
576 status = torture_setup_unix_extensions(cli_unix);
577 if (!NT_STATUS_IS_OK(status)) {
578 TALLOC_FREE(frame);
579 return false;
582 cli_posix_unlink(cli_unix, file);
583 cli_posix_unlink(cli_unix, symlnk_dangling);
584 cli_posix_unlink(cli_unix, symlnk_in_share);
585 cli_posix_unlink(cli_unix, symlnk_outside_share);
587 status = cli_posix_open(cli_unix,
588 file,
589 O_RDWR|O_CREAT,
590 0666,
591 &fnum);
592 if (!NT_STATUS_IS_OK(status)) {
593 printf("cli_posix_open of %s failed error %s\n",
594 file,
595 nt_errstr(status));
596 goto out;
599 status = cli_close(cli_unix, fnum);
600 if (!NT_STATUS_IS_OK(status)) {
601 printf("cli_close failed %s\n", nt_errstr(status));
602 goto out;
604 fnum = (uint16_t)-1;
606 for (i = 0; entries[i].name != NULL; i++) {
607 status = cli_posix_symlink(cli_unix,
608 entries[i].target,
609 entries[i].name);
610 if (!NT_STATUS_IS_OK(status)) {
611 printf("POSIX symlink of %s failed (%s)\n",
612 symlnk_dangling, nt_errstr(status));
613 goto out;
617 for (i = 0; entries[i].name != NULL; i++) {
618 char *target = NULL;
620 status = cli_readlink(
621 cli_unix,
622 entries[i].name,
623 talloc_tos(),
624 &target,
625 NULL,
626 NULL);
627 if (!NT_STATUS_IS_OK(status)) {
628 printf("POSIX readlink on %s failed (%s)\n",
629 entries[i].name, nt_errstr(status));
630 goto out;
632 if (strequal(target, entries[i].target)) {
633 entries[i].ok = true;
634 entries[i].returned_size = strlen(target);
638 if (!posix_test_entry_check(state,
639 symlnk_dangling,
640 true,
641 strlen(symlnk_dst_dangling)))
643 goto out;
645 if (!posix_test_entry_check(state,
646 symlnk_outside_share,
647 true,
648 strlen(symlnk_dst_outside_share)))
650 goto out;
652 if (!posix_test_entry_check(state,
653 symlnk_in_share,
654 true,
655 strlen(symlnk_dst_in_share))) {
656 goto out;
659 printf("POSIX-READLINK test passed\n");
660 correct = true;
662 out:
663 cli_posix_unlink(cli_unix, file);
664 cli_posix_unlink(cli_unix, symlnk_dangling);
665 cli_posix_unlink(cli_unix, symlnk_in_share);
666 cli_posix_unlink(cli_unix, symlnk_outside_share);
668 if (!torture_close_connection(cli_unix)) {
669 correct = false;
672 TALLOC_FREE(frame);
673 return correct;
677 Test POSIX stat of symlinks
679 bool run_posix_stat_test(int dummy)
681 TALLOC_CTX *frame = NULL;
682 struct cli_state *cli_unix = NULL;
683 uint16_t fnum = (uint16_t)-1;
684 NTSTATUS status;
685 const char *file = "file";
686 const char *symlnk_dangling = "dangling";
687 const char *symlnk_dst_dangling = "xxxxxxx";
688 const char *symlnk_in_share = "symlnk_in_share";
689 const char *symlnk_dst_in_share = file;
690 const char *symlnk_outside_share = "symlnk_outside_share";
691 const char *symlnk_dst_outside_share = "/etc/passwd";
692 struct posix_test_entry entries[] = {
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,
709 struct posix_test_state _state = {
710 .entries = &entries[0],
712 struct posix_test_state *state = &_state;
713 int i;
714 bool correct = false;
716 frame = talloc_stackframe();
718 printf("Starting POSIX-STAT test\n");
719 state->flavour = POSIX;
721 if (!torture_open_connection(&cli_unix, 0)) {
722 TALLOC_FREE(frame);
723 return false;
726 torture_conn_set_sockopt(cli_unix);
728 status = torture_setup_unix_extensions(cli_unix);
729 if (!NT_STATUS_IS_OK(status)) {
730 TALLOC_FREE(frame);
731 return false;
734 cli_posix_unlink(cli_unix, file);
735 cli_posix_unlink(cli_unix, symlnk_dangling);
736 cli_posix_unlink(cli_unix, symlnk_in_share);
737 cli_posix_unlink(cli_unix, symlnk_outside_share);
739 status = cli_posix_open(cli_unix,
740 file,
741 O_RDWR|O_CREAT,
742 0666,
743 &fnum);
744 if (!NT_STATUS_IS_OK(status)) {
745 printf("cli_posix_open of %s failed error %s\n",
746 file,
747 nt_errstr(status));
748 goto out;
751 status = cli_close(cli_unix, fnum);
752 if (!NT_STATUS_IS_OK(status)) {
753 printf("cli_close failed %s\n", nt_errstr(status));
754 goto out;
756 fnum = (uint16_t)-1;
758 for (i = 0; entries[i].name != NULL; i++) {
759 status = cli_posix_symlink(cli_unix,
760 entries[i].target,
761 entries[i].name);
762 if (!NT_STATUS_IS_OK(status)) {
763 printf("POSIX symlink of %s failed (%s)\n",
764 symlnk_dangling, nt_errstr(status));
765 goto out;
769 for (i = 0; entries[i].name != NULL; i++) {
770 SMB_STRUCT_STAT sbuf;
772 status = cli_posix_stat(cli_unix,
773 entries[i].name,
774 &sbuf);
775 if (!NT_STATUS_IS_OK(status)) {
776 printf("POSIX stat on %s failed (%s)\n",
777 entries[i].name, nt_errstr(status));
778 continue;
780 entries[i].ok = true;
781 entries[i].returned_size = sbuf.st_ex_size;
784 if (!posix_test_entry_check(state,
785 symlnk_dangling,
786 true,
787 strlen(symlnk_dst_dangling)))
789 goto out;
791 if (!posix_test_entry_check(state,
792 symlnk_outside_share,
793 true,
794 strlen(symlnk_dst_outside_share)))
796 goto out;
798 if (!posix_test_entry_check(state,
799 symlnk_in_share,
800 true,
801 strlen(symlnk_dst_in_share))) {
802 goto out;
805 printf("POSIX-STAT test passed\n");
806 correct = true;
808 out:
809 cli_posix_unlink(cli_unix, file);
810 cli_posix_unlink(cli_unix, symlnk_dangling);
811 cli_posix_unlink(cli_unix, symlnk_in_share);
812 cli_posix_unlink(cli_unix, symlnk_outside_share);
814 if (!torture_close_connection(cli_unix)) {
815 correct = false;
818 TALLOC_FREE(frame);
819 return correct;
823 Test Creating files and directories directly
824 under a symlink.
826 bool run_posix_symlink_parent_test(int dummy)
828 TALLOC_CTX *frame = NULL;
829 struct cli_state *cli_unix = NULL;
830 uint16_t fnum = (uint16_t)-1;
831 NTSTATUS status;
832 const char *parent_dir = "target_dir";
833 const char *parent_symlink = "symlink_to_target_dir";
834 const char *fname_real = "target_dir/file";
835 const char *dname_real = "target_dir/dir";
836 const char *fname_link = "symlink_to_target_dir/file";
837 const char *dname_link = "symlink_to_target_dir/dir";
838 const char *sname_link = "symlink_to_target_dir/symlink";
839 const char *hname_link = "symlink_to_target_dir/hardlink";
840 bool correct = false;
842 frame = talloc_stackframe();
844 printf("Starting POSIX-SYMLINK-PARENT test\n");
846 if (!torture_open_connection(&cli_unix, 0)) {
847 TALLOC_FREE(frame);
848 return false;
851 torture_conn_set_sockopt(cli_unix);
853 status = torture_setup_unix_extensions(cli_unix);
854 if (!NT_STATUS_IS_OK(status)) {
855 TALLOC_FREE(frame);
856 return false;
859 /* Start with a clean slate. */
860 cli_posix_unlink(cli_unix, fname_real);
861 cli_posix_rmdir(cli_unix, dname_real);
862 cli_posix_unlink(cli_unix, fname_link);
863 cli_posix_rmdir(cli_unix, dname_link);
864 cli_posix_unlink(cli_unix, sname_link);
865 cli_posix_unlink(cli_unix, hname_link);
866 cli_posix_unlink(cli_unix, parent_symlink);
867 cli_posix_rmdir(cli_unix, parent_dir);
869 /* Create parent_dir. */
870 status = cli_posix_mkdir(cli_unix, parent_dir, 0777);
871 if (!NT_STATUS_IS_OK(status)) {
872 printf("cli_posix_mkdir of %s failed error %s\n",
873 parent_dir,
874 nt_errstr(status));
875 goto out;
877 /* Create symlink to parent_dir. */
878 status = cli_posix_symlink(cli_unix,
879 parent_dir,
880 parent_symlink);
881 if (!NT_STATUS_IS_OK(status)) {
882 printf("cli_posix_symlink of %s -> %s failed error %s\n",
883 parent_symlink,
884 parent_dir,
885 nt_errstr(status));
886 goto out;
888 /* Try and create a directory under the symlink. */
889 status = cli_posix_mkdir(cli_unix, dname_link, 0777);
890 if (!NT_STATUS_IS_OK(status)) {
891 printf("cli_posix_mkdir of %s failed error %s\n",
892 dname_link,
893 nt_errstr(status));
894 goto out;
896 /* Try and create a file under the symlink. */
897 status = cli_posix_open(cli_unix,
898 fname_link,
899 O_RDWR|O_CREAT,
900 0666,
901 &fnum);
902 if (!NT_STATUS_IS_OK(status)) {
903 printf("cli_posix_open of %s failed error %s\n",
904 fname_link,
905 nt_errstr(status));
906 goto out;
908 status = cli_close(cli_unix, fnum);
909 if (!NT_STATUS_IS_OK(status)) {
910 printf("cli_close failed %s\n", nt_errstr(status));
911 goto out;
913 fnum = (uint16_t)-1;
915 /* Try and create a symlink to the file under the symlink. */
916 status = cli_posix_symlink(cli_unix,
917 fname_link,
918 sname_link);
919 if (!NT_STATUS_IS_OK(status)) {
920 printf("cli_posix_symlink of %s -> %s failed error %s\n",
921 sname_link,
922 fname_link,
923 nt_errstr(status));
924 goto out;
927 /* Try and create a hardlink to the file under the symlink. */
928 status = cli_posix_hardlink(cli_unix,
929 fname_link,
930 hname_link);
931 if (!NT_STATUS_IS_OK(status)) {
932 printf("cli_posix_hardlink of %s -> %s failed error %s\n",
933 hname_link,
934 fname_link,
935 nt_errstr(status));
936 goto out;
939 /* Ensure we can delete the symlink via the parent symlink */
940 status = cli_posix_unlink(cli_unix, sname_link);
941 if (!NT_STATUS_IS_OK(status)) {
942 printf("cli_posix_unlink of %s failed error %s\n",
943 sname_link,
944 nt_errstr(status));
945 goto out;
948 /* Ensure we can delete the hardlink via the parent symlink */
949 status = cli_posix_unlink(cli_unix, hname_link);
950 if (!NT_STATUS_IS_OK(status)) {
951 printf("cli_posix_unlink of %s failed error %s\n",
952 hname_link,
953 nt_errstr(status));
954 goto out;
957 /* Ensure we can delete the directory via the parent symlink */
958 status = cli_posix_rmdir(cli_unix, dname_link);
959 if (!NT_STATUS_IS_OK(status)) {
960 printf("cli_posix_rmdir of %s failed error %s\n",
961 dname_link,
962 nt_errstr(status));
963 goto out;
965 /* Ensure we can delete the file via the parent symlink */
966 status = cli_posix_unlink(cli_unix, fname_link);
967 if (!NT_STATUS_IS_OK(status)) {
968 printf("cli_posix_unlink of %s failed error %s\n",
969 fname_link,
970 nt_errstr(status));
971 goto out;
974 printf("POSIX-SYMLINK-PARENT test passed\n");
975 correct = true;
977 out:
978 if (fnum != (uint16_t)-1) {
979 cli_close(cli_unix, fnum);
981 cli_posix_unlink(cli_unix, fname_real);
982 cli_posix_rmdir(cli_unix, dname_real);
983 cli_posix_unlink(cli_unix, fname_link);
984 cli_posix_rmdir(cli_unix, dname_link);
985 cli_posix_unlink(cli_unix, sname_link);
986 cli_posix_unlink(cli_unix, hname_link);
987 cli_posix_unlink(cli_unix, parent_symlink);
988 cli_posix_rmdir(cli_unix, parent_dir);
990 if (!torture_close_connection(cli_unix)) {
991 correct = false;
994 TALLOC_FREE(frame);
995 return correct;
999 Ensure we get an error when doing chmod on a symlink,
1000 whether it is pointing to a real object or dangling.
1002 bool run_posix_symlink_chmod_test(int dummy)
1004 TALLOC_CTX *frame = NULL;
1005 struct cli_state *cli_unix = NULL;
1006 NTSTATUS status;
1007 uint16_t fnum = (uint16_t)-1;
1008 const char *fname_real = "file_real";
1009 const char *fname_real_symlink = "file_real_symlink";
1010 const char *nonexist = "nonexist";
1011 const char *nonexist_symlink = "dangling_symlink";
1012 bool correct = false;
1014 frame = talloc_stackframe();
1016 printf("Starting POSIX-SYMLINK-CHMOD test\n");
1018 if (!torture_open_connection(&cli_unix, 0)) {
1019 TALLOC_FREE(frame);
1020 return false;
1023 torture_conn_set_sockopt(cli_unix);
1025 status = torture_setup_unix_extensions(cli_unix);
1026 if (!NT_STATUS_IS_OK(status)) {
1027 TALLOC_FREE(frame);
1028 return false;
1031 /* Start with a clean slate. */
1032 cli_posix_unlink(cli_unix, fname_real);
1033 cli_posix_unlink(cli_unix, fname_real_symlink);
1034 cli_posix_unlink(cli_unix, nonexist);
1035 cli_posix_unlink(cli_unix, nonexist_symlink);
1037 /* Create a real file. */
1038 status = cli_posix_open(cli_unix,
1039 fname_real,
1040 O_RDWR|O_CREAT,
1041 0644,
1042 &fnum);
1043 if (!NT_STATUS_IS_OK(status)) {
1044 printf("cli_posix_open of %s failed error %s\n",
1045 fname_real,
1046 nt_errstr(status));
1047 goto out;
1049 status = cli_close(cli_unix, fnum);
1050 if (!NT_STATUS_IS_OK(status)) {
1051 printf("cli_close failed %s\n", nt_errstr(status));
1052 goto out;
1054 fnum = (uint16_t)-1;
1056 /* Create symlink to real target. */
1057 status = cli_posix_symlink(cli_unix,
1058 fname_real,
1059 fname_real_symlink);
1060 if (!NT_STATUS_IS_OK(status)) {
1061 printf("cli_posix_symlink of %s -> %s failed error %s\n",
1062 fname_real_symlink,
1063 fname_real,
1064 nt_errstr(status));
1065 goto out;
1068 /* We should not be able to chmod symlinks that point to something. */
1069 status = cli_posix_chmod(cli_unix, fname_real_symlink, 0777);
1071 /* This should fail with something other than server crashed. */
1072 if (NT_STATUS_IS_OK(status)) {
1073 printf("cli_posix_chmod of %s succeeded (should have failed)\n",
1074 fname_real_symlink);
1075 goto out;
1077 if (NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_DISCONNECTED)) {
1078 /* Oops. Server crashed. */
1079 printf("cli_posix_chmod of %s failed error %s\n",
1080 fname_real_symlink,
1081 nt_errstr(status));
1082 goto out;
1084 /* Any other failure is ok. */
1086 /* Now create symlink to non-existing target. */
1087 status = cli_posix_symlink(cli_unix,
1088 nonexist,
1089 nonexist_symlink);
1090 if (!NT_STATUS_IS_OK(status)) {
1091 printf("cli_posix_symlink of %s -> %s failed error %s\n",
1092 nonexist_symlink,
1093 nonexist,
1094 nt_errstr(status));
1095 goto out;
1098 /* We should not be able to chmod symlinks that point to nothing. */
1099 status = cli_posix_chmod(cli_unix, nonexist_symlink, 0777);
1101 /* This should fail with something other than server crashed. */
1102 if (NT_STATUS_IS_OK(status)) {
1103 printf("cli_posix_chmod of %s succeeded (should have failed)\n",
1104 nonexist_symlink);
1105 goto out;
1107 if (NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_DISCONNECTED)) {
1108 /* Oops. Server crashed. */
1109 printf("cli_posix_chmod of %s failed error %s\n",
1110 nonexist_symlink,
1111 nt_errstr(status));
1112 goto out;
1115 /* Any other failure is ok. */
1116 printf("POSIX-SYMLINK-CHMOD test passed (expected failure was %s)\n",
1117 nt_errstr(status));
1118 correct = true;
1120 out:
1121 if (fnum != (uint16_t)-1) {
1122 cli_close(cli_unix, fnum);
1124 cli_posix_unlink(cli_unix, fname_real);
1125 cli_posix_unlink(cli_unix, fname_real_symlink);
1126 cli_posix_unlink(cli_unix, nonexist);
1127 cli_posix_unlink(cli_unix, nonexist_symlink);
1129 if (!torture_close_connection(cli_unix)) {
1130 correct = false;
1133 TALLOC_FREE(frame);
1134 return correct;
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.
1143 bool run_posix_dir_default_acl_test(int dummy)
1145 TALLOC_CTX *frame = NULL;
1146 struct cli_state *cli_unix = NULL;
1147 NTSTATUS status;
1148 uint16_t fnum = (uint16_t)-1;
1149 const char *dname = "dir_with_default_acl";
1150 bool correct = false;
1151 SMB_STRUCT_STAT sbuf;
1152 size_t acl_size = 0;
1153 char *aclbuf = NULL;
1154 size_t num_file_acls = 0;
1155 size_t num_dir_acls = 0;
1156 size_t expected_buflen;
1157 uint8_t def_acl[SMB_POSIX_ACL_HEADER_SIZE +
1158 5*SMB_POSIX_ACL_ENTRY_SIZE] = {0};
1159 uint8_t *p = NULL;
1160 uint32_t i = 0;
1161 struct security_descriptor *sd = NULL;
1162 bool got_inherit = false;
1164 frame = talloc_stackframe();
1166 printf("Starting POSIX-DIR-DEFAULT-ACL test\n");
1168 if (!torture_open_connection(&cli_unix, 0)) {
1169 TALLOC_FREE(frame);
1170 return false;
1173 torture_conn_set_sockopt(cli_unix);
1175 status = torture_setup_unix_extensions(cli_unix);
1176 if (!NT_STATUS_IS_OK(status)) {
1177 TALLOC_FREE(frame);
1178 return false;
1181 /* Start with a clean slate. */
1182 cli_posix_unlink(cli_unix, dname);
1183 cli_posix_rmdir(cli_unix, dname);
1185 status = cli_posix_mkdir(cli_unix, dname, 0777);
1186 if (!NT_STATUS_IS_OK(status)) {
1187 printf("cli_posix_mkdir of %s failed error %s\n",
1188 dname,
1189 nt_errstr(status));
1190 goto out;
1193 /* Do a posix stat to get the owner. */
1194 status = cli_posix_stat(cli_unix, dname, &sbuf);
1195 if (!NT_STATUS_IS_OK(status)) {
1196 printf("cli_posix_stat of %s failed %s\n",
1197 dname,
1198 nt_errstr(status));
1199 goto out;
1202 /* Get the ACL on the directory. */
1203 status = cli_posix_getacl(cli_unix, dname, frame, &acl_size, &aclbuf);
1204 if (!NT_STATUS_IS_OK(status)) {
1205 printf("cli_posix_getacl on %s failed %s\n",
1206 dname,
1207 nt_errstr(status));
1208 goto out;
1211 if (acl_size < 6 || SVAL(aclbuf,0) != SMB_POSIX_ACL_VERSION) {
1212 printf("%s, unknown POSIX acl version %u.\n",
1213 dname,
1214 (unsigned int)CVAL(aclbuf,0) );
1215 goto out;
1218 num_file_acls = SVAL(aclbuf,2);
1219 num_dir_acls = SVAL(aclbuf,4);
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.
1226 expected_buflen = SMB_POSIX_ACL_HEADER_SIZE +
1227 SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls);
1229 if (acl_size != expected_buflen) {
1230 printf("%s, incorrect POSIX acl buffer size "
1231 "(should be %zu, was %zu).\n",
1232 dname,
1233 expected_buflen,
1234 acl_size);
1235 goto out;
1238 if (num_dir_acls != 0) {
1239 printf("%s, POSIX default acl already exists"
1240 "(should be 0, was %zu).\n",
1241 dname,
1242 num_dir_acls);
1243 goto out;
1247 * Get the Windows ACL on the directory.
1248 * Make sure there are no inheritable entries.
1250 status = cli_ntcreate(cli_unix,
1251 dname,
1253 SEC_STD_READ_CONTROL,
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 if (!NT_STATUS_IS_OK(status)) {
1264 printf("Failed to open directory %s: %s\n",
1265 dname,
1266 nt_errstr(status));
1267 goto out;
1270 status = cli_query_security_descriptor(cli_unix,
1271 fnum,
1272 SECINFO_DACL,
1273 frame,
1274 &sd);
1275 if (!NT_STATUS_IS_OK(status)) {
1276 printf("Failed to get security descriptor on directory %s: %s\n",
1277 dname,
1278 nt_errstr(status));
1279 goto out;
1282 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1283 struct security_ace *ace = &sd->dacl->aces[i];
1284 if (ace->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
1285 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
1286 printf("security descriptor on directory %s already "
1287 "contains inheritance flags\n",
1288 dname);
1289 sec_desc_print(NULL, stdout, sd, true);
1290 goto out;
1294 TALLOC_FREE(sd);
1296 /* Construct a new default ACL. */
1297 SSVAL(def_acl,0,SMB_POSIX_ACL_VERSION);
1298 SSVAL(def_acl,2,SMB_POSIX_IGNORE_ACE_ENTRIES);
1299 SSVAL(def_acl,4,5); /* num_dir_acls. */
1301 p = def_acl + SMB_POSIX_ACL_HEADER_SIZE;
1303 /* USER_OBJ. */
1304 SCVAL(p,0,SMB_POSIX_ACL_USER_OBJ); /* tagtype. */
1305 SCVAL(p,1,SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE);
1306 p += SMB_POSIX_ACL_ENTRY_SIZE;
1308 /* GROUP_OBJ. */
1309 SCVAL(p,0,SMB_POSIX_ACL_GROUP_OBJ); /* tagtype. */
1310 SCVAL(p,1,SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE);
1311 p += SMB_POSIX_ACL_ENTRY_SIZE;
1313 /* OTHER. */
1314 SCVAL(p,0,SMB_POSIX_ACL_OTHER); /* tagtype. */
1315 SCVAL(p,1,SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE);
1316 p += SMB_POSIX_ACL_ENTRY_SIZE;
1318 /* Explicit user. */
1319 SCVAL(p,0,SMB_POSIX_ACL_USER); /* tagtype. */
1320 SCVAL(p,1,SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE);
1321 SIVAL(p,2,sbuf.st_ex_uid);
1322 p += SMB_POSIX_ACL_ENTRY_SIZE;
1324 /* MASK. */
1325 SCVAL(p,0,SMB_POSIX_ACL_MASK); /* tagtype. */
1326 SCVAL(p,1,SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE);
1327 p += SMB_POSIX_ACL_ENTRY_SIZE;
1329 /* Set the POSIX default ACL. */
1330 status = cli_posix_setacl(cli_unix, dname, def_acl, sizeof(def_acl));
1331 if (!NT_STATUS_IS_OK(status)) {
1332 printf("cli_posix_setacl on %s failed %s\n",
1333 dname,
1334 nt_errstr(status));
1335 goto out;
1339 * Get the Windows ACL on the directory again.
1340 * Now there should be inheritable entries.
1343 status = cli_query_security_descriptor(cli_unix,
1344 fnum,
1345 SECINFO_DACL,
1346 frame,
1347 &sd);
1348 if (!NT_STATUS_IS_OK(status)) {
1349 printf("Failed (2) to get security descriptor "
1350 "on directory %s: %s\n",
1351 dname,
1352 nt_errstr(status));
1353 goto out;
1356 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1357 struct security_ace *ace = &sd->dacl->aces[i];
1358 if (ace->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
1359 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
1360 got_inherit = true;
1361 break;
1365 if (!got_inherit) {
1366 printf("security descriptor on directory %s does not "
1367 "contain inheritance flags\n",
1368 dname);
1369 sec_desc_print(NULL, stdout, sd, true);
1370 goto out;
1373 cli_close(cli_unix, fnum);
1374 fnum = (uint16_t)-1;
1375 printf("POSIX-DIR-DEFAULT-ACL test passed\n");
1376 correct = true;
1378 out:
1380 TALLOC_FREE(sd);
1382 if (fnum != (uint16_t)-1) {
1383 cli_close(cli_unix, fnum);
1385 cli_posix_unlink(cli_unix, dname);
1386 cli_posix_rmdir(cli_unix, dname);
1388 if (!torture_close_connection(cli_unix)) {
1389 correct = false;
1392 TALLOC_FREE(frame);
1393 return correct;
1397 Ensure we can rename a symlink whether it is
1398 pointing to a real object or dangling.
1400 bool run_posix_symlink_rename_test(int dummy)
1402 TALLOC_CTX *frame = NULL;
1403 struct cli_state *cli_unix = NULL;
1404 NTSTATUS status;
1405 uint16_t fnum = (uint16_t)-1;
1406 const char *fname_real = "file_real";
1407 const char *fname_real_symlink = "file_real_symlink";
1408 const char *fname_real_symlink_newname = "rename_file_real_symlink";
1409 const char *nonexist = "nonexist";
1410 const char *nonexist_symlink = "dangling_symlink";
1411 const char *nonexist_symlink_newname = "dangling_symlink_rename";
1412 bool correct = false;
1414 frame = talloc_stackframe();
1416 printf("Starting POSIX-SYMLINK-RENAME test\n");
1418 if (!torture_open_connection(&cli_unix, 0)) {
1419 TALLOC_FREE(frame);
1420 return false;
1423 torture_conn_set_sockopt(cli_unix);
1425 status = torture_setup_unix_extensions(cli_unix);
1426 if (!NT_STATUS_IS_OK(status)) {
1427 TALLOC_FREE(frame);
1428 return false;
1431 /* Start with a clean slate. */
1432 cli_posix_unlink(cli_unix, fname_real);
1433 cli_posix_unlink(cli_unix, fname_real_symlink);
1434 cli_posix_unlink(cli_unix, fname_real_symlink_newname);
1435 cli_posix_unlink(cli_unix, nonexist);
1436 cli_posix_unlink(cli_unix, nonexist_symlink);
1437 cli_posix_unlink(cli_unix, nonexist_symlink_newname);
1439 /* Create a real file. */
1440 status = cli_posix_open(cli_unix,
1441 fname_real,
1442 O_RDWR|O_CREAT,
1443 0644,
1444 &fnum);
1445 if (!NT_STATUS_IS_OK(status)) {
1446 printf("cli_posix_open of %s failed error %s\n",
1447 fname_real,
1448 nt_errstr(status));
1449 goto out;
1451 status = cli_close(cli_unix, fnum);
1452 if (!NT_STATUS_IS_OK(status)) {
1453 printf("cli_close failed %s\n", nt_errstr(status));
1454 goto out;
1456 fnum = (uint16_t)-1;
1458 /* Create symlink to real target. */
1459 status = cli_posix_symlink(cli_unix,
1460 fname_real,
1461 fname_real_symlink);
1462 if (!NT_STATUS_IS_OK(status)) {
1463 printf("cli_posix_symlink of %s -> %s failed error %s\n",
1464 fname_real_symlink,
1465 fname_real,
1466 nt_errstr(status));
1467 goto out;
1470 /* Ensure we can rename the symlink to the real file. */
1471 status = cli_rename(cli_unix,
1472 fname_real_symlink,
1473 fname_real_symlink_newname,
1474 false);
1475 if (!NT_STATUS_IS_OK(status)) {
1476 printf("cli_rename of %s -> %s failed %s\n",
1477 fname_real_symlink,
1478 fname_real_symlink_newname,
1479 nt_errstr(status));
1480 goto out;
1483 /* Now create symlink to non-existing target. */
1484 status = cli_posix_symlink(cli_unix,
1485 nonexist,
1486 nonexist_symlink);
1487 if (!NT_STATUS_IS_OK(status)) {
1488 printf("cli_posix_symlink of %s -> %s failed error %s\n",
1489 nonexist_symlink,
1490 nonexist,
1491 nt_errstr(status));
1492 goto out;
1495 /* Ensure we can rename the dangling symlink. */
1496 status = cli_rename(cli_unix,
1497 nonexist_symlink,
1498 nonexist_symlink_newname,
1499 false);
1500 if (!NT_STATUS_IS_OK(status)) {
1501 printf("cli_rename of %s -> %s failed %s\n",
1502 nonexist_symlink,
1503 nonexist_symlink_newname,
1504 nt_errstr(status));
1505 goto out;
1508 printf("POSIX-SYMLINK-RENAME test passed\n");
1509 correct = true;
1511 out:
1512 if (fnum != (uint16_t)-1) {
1513 cli_close(cli_unix, fnum);
1515 cli_posix_unlink(cli_unix, fname_real);
1516 cli_posix_unlink(cli_unix, fname_real_symlink);
1517 cli_posix_unlink(cli_unix, fname_real_symlink_newname);
1518 cli_posix_unlink(cli_unix, nonexist);
1519 cli_posix_unlink(cli_unix, nonexist_symlink);
1520 cli_posix_unlink(cli_unix, nonexist_symlink_newname);
1522 if (!torture_close_connection(cli_unix)) {
1523 correct = false;
1526 TALLOC_FREE(frame);
1527 return correct;
1530 /* List of info levels to try with a POSIX symlink path. */
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"},
1568 static NTSTATUS do_qpath(TALLOC_CTX *ctx,
1569 struct cli_state *cli_unix,
1570 const char *fname,
1571 size_t i)
1573 NTSTATUS status;
1575 if (posix_smb1_qpath_array[i].level ==
1576 SMB_INFO_QUERY_EAS_FROM_LIST) {
1577 uint16_t setup;
1578 uint8_t *param;
1579 uint8_t data[8];
1580 uint8_t *rparam = NULL;
1581 uint8_t *rdata = NULL;
1582 uint32_t rbytes = 0;
1584 /* Set up an EA list with 'a' as the single name. */
1585 SIVAL(data,0, 8);
1586 SCVAL(data,4, 2); /* namelen. */
1587 SCVAL(data,5, 'a');
1588 SCVAL(data,6, '\0'); /* name. */
1589 SCVAL(data,7, '\0'); /* padding. */
1591 SSVAL(&setup, 0, TRANSACT2_QPATHINFO);
1593 param = talloc_zero_array(ctx, uint8_t, 6);
1594 if (param == NULL) {
1595 return NT_STATUS_NO_MEMORY;
1597 SSVAL(param, 0, SMB_INFO_QUERY_EAS_FROM_LIST);
1598 param = trans2_bytes_push_str(param,
1599 smbXcli_conn_use_unicode(cli_unix->conn),
1600 fname,
1601 strlen(fname)+1,
1602 NULL);
1603 if (param == NULL) {
1604 return NT_STATUS_NO_MEMORY;
1607 status = cli_trans(ctx,
1608 cli_unix,
1609 SMBtrans2,
1610 NULL,
1614 &setup, 1, 0,
1615 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 TALLOC_FREE(rparam);
1622 TALLOC_FREE(rdata);
1623 } else {
1624 uint8_t *rdata = NULL;
1625 uint32_t num_rdata = 0;
1627 status = cli_qpathinfo(ctx,
1628 cli_unix,
1629 fname,
1630 posix_smb1_qpath_array[i].level,
1631 0, /* min_rdata */
1632 65534, /* max_rdata */
1633 &rdata,
1634 &num_rdata);
1635 TALLOC_FREE(rdata);
1638 * We don't care what came back, so long as the
1639 * server didn't crash.
1641 if (NT_STATUS_EQUAL(status,
1642 NT_STATUS_CONNECTION_DISCONNECTED)) {
1643 printf("cli_qpathinfo of %s failed error "
1644 "NT_STATUS_CONNECTION_DISCONNECTED\n",
1645 fname);
1646 return status;
1649 printf("cli_qpathinfo info %x (%s) of %s got %s "
1650 "(this is not an error)\n",
1651 (unsigned int)posix_smb1_qpath_array[i].level,
1652 posix_smb1_qpath_array[i].name,
1653 fname,
1654 nt_errstr(status));
1656 return NT_STATUS_OK;
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.
1664 bool run_posix_symlink_getpathinfo_test(int dummy)
1666 TALLOC_CTX *frame = NULL;
1667 struct cli_state *cli_unix = NULL;
1668 NTSTATUS status;
1669 uint16_t fnum = (uint16_t)-1;
1670 const char *fname_real = "file_getpath_real";
1671 const char *fname_real_symlink = "file_real_getpath_symlink";
1672 const char *nonexist = "nonexist_getpath";
1673 const char *nonexist_symlink = "dangling_getpath_symlink";
1674 bool correct = false;
1675 size_t i;
1677 frame = talloc_stackframe();
1679 printf("Starting POSIX-SYMLINK-GETPATHINFO test\n");
1681 if (!torture_open_connection(&cli_unix, 0)) {
1682 TALLOC_FREE(frame);
1683 return false;
1686 torture_conn_set_sockopt(cli_unix);
1688 status = torture_setup_unix_extensions(cli_unix);
1689 if (!NT_STATUS_IS_OK(status)) {
1690 TALLOC_FREE(frame);
1691 return false;
1694 /* Start with a clean slate. */
1695 cli_posix_unlink(cli_unix, fname_real);
1696 cli_posix_unlink(cli_unix, fname_real_symlink);
1697 cli_posix_unlink(cli_unix, nonexist);
1698 cli_posix_unlink(cli_unix, nonexist_symlink);
1700 /* Create a real file. */
1701 status = cli_posix_open(cli_unix,
1702 fname_real,
1703 O_RDWR|O_CREAT,
1704 0644,
1705 &fnum);
1706 if (!NT_STATUS_IS_OK(status)) {
1707 printf("cli_posix_open of %s failed error %s\n",
1708 fname_real,
1709 nt_errstr(status));
1710 goto out;
1712 status = cli_close(cli_unix, fnum);
1713 if (!NT_STATUS_IS_OK(status)) {
1714 printf("cli_close failed %s\n", nt_errstr(status));
1715 goto out;
1717 fnum = (uint16_t)-1;
1719 /* Create symlink to real target. */
1720 status = cli_posix_symlink(cli_unix,
1721 fname_real,
1722 fname_real_symlink);
1723 if (!NT_STATUS_IS_OK(status)) {
1724 printf("cli_posix_symlink of %s -> %s failed error %s\n",
1725 fname_real_symlink,
1726 fname_real,
1727 nt_errstr(status));
1728 goto out;
1731 /* Now create symlink to non-existing target. */
1732 status = cli_posix_symlink(cli_unix,
1733 nonexist,
1734 nonexist_symlink);
1735 if (!NT_STATUS_IS_OK(status)) {
1736 printf("cli_posix_symlink of %s -> %s failed error %s\n",
1737 nonexist_symlink,
1738 nonexist,
1739 nt_errstr(status));
1740 goto out;
1743 for (i = 0; i < ARRAY_SIZE(posix_smb1_qpath_array); i++) {
1744 status = do_qpath(frame,
1745 cli_unix,
1746 fname_real_symlink,
1748 if (!NT_STATUS_IS_OK(status)) {
1749 goto out;
1751 status = do_qpath(frame,
1752 cli_unix,
1753 nonexist_symlink,
1755 if (!NT_STATUS_IS_OK(status)) {
1756 goto out;
1760 printf("POSIX-SYMLINK-GETPATHINFO test passed\n");
1761 correct = true;
1763 out:
1764 if (fnum != (uint16_t)-1) {
1765 cli_close(cli_unix, fnum);
1767 cli_posix_unlink(cli_unix, fname_real);
1768 cli_posix_unlink(cli_unix, fname_real_symlink);
1769 cli_posix_unlink(cli_unix, nonexist);
1770 cli_posix_unlink(cli_unix, nonexist_symlink);
1772 if (!torture_close_connection(cli_unix)) {
1773 correct = false;
1776 TALLOC_FREE(frame);
1777 return correct;
1780 /* List of info levels to try with a POSIX symlink path. */
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},
1807 static NTSTATUS do_setpath(TALLOC_CTX *ctx,
1808 struct cli_state *cli_unix,
1809 const char *fname,
1810 size_t i)
1812 NTSTATUS status;
1813 uint8_t *data = NULL;
1815 data = talloc_zero_array(ctx,
1816 uint8_t,
1817 posix_smb1_setpath_array[i].data_len);
1818 if (data == NULL) {
1819 return NT_STATUS_NO_MEMORY;
1822 status = cli_setpathinfo(cli_unix,
1823 posix_smb1_setpath_array[i].level,
1824 fname,
1825 data,
1826 posix_smb1_setpath_array[i].data_len);
1827 TALLOC_FREE(data);
1830 * We don't care what came back, so long as the
1831 * server didn't crash.
1833 if (NT_STATUS_EQUAL(status,
1834 NT_STATUS_CONNECTION_DISCONNECTED)) {
1835 printf("cli_setpathinfo info %x (%s) of %s failed"
1836 "error NT_STATUS_CONNECTION_DISCONNECTED\n",
1837 (unsigned int)posix_smb1_setpath_array[i].level,
1838 posix_smb1_setpath_array[i].name,
1839 fname);
1840 return status;
1843 printf("cli_setpathinfo info %x (%s) of %s got %s "
1844 "(this is not an error)\n",
1845 (unsigned int)posix_smb1_setpath_array[i].level,
1846 posix_smb1_setpath_array[i].name,
1847 fname,
1848 nt_errstr(status));
1850 return NT_STATUS_OK;
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.
1858 bool run_posix_symlink_setpathinfo_test(int dummy)
1860 TALLOC_CTX *frame = NULL;
1861 struct cli_state *cli_unix = NULL;
1862 NTSTATUS status;
1863 uint16_t fnum = (uint16_t)-1;
1864 const char *fname_real = "file_setpath_real";
1865 const char *fname_real_symlink = "file_real_setpath_symlink";
1866 const char *nonexist = "nonexist_setpath";
1867 const char *nonexist_symlink = "dangling_setpath_symlink";
1868 bool correct = false;
1869 size_t i;
1871 frame = talloc_stackframe();
1873 printf("Starting POSIX-SYMLINK-SETPATHINFO test\n");
1875 if (!torture_open_connection(&cli_unix, 0)) {
1876 TALLOC_FREE(frame);
1877 return false;
1880 torture_conn_set_sockopt(cli_unix);
1882 status = torture_setup_unix_extensions(cli_unix);
1883 if (!NT_STATUS_IS_OK(status)) {
1884 TALLOC_FREE(frame);
1885 return false;
1888 /* Start with a clean slate. */
1889 cli_posix_unlink(cli_unix, fname_real);
1890 cli_posix_unlink(cli_unix, fname_real_symlink);
1891 cli_posix_unlink(cli_unix, nonexist);
1892 cli_posix_unlink(cli_unix, nonexist_symlink);
1894 /* Create a real file. */
1895 status = cli_posix_open(cli_unix,
1896 fname_real,
1897 O_RDWR|O_CREAT,
1898 0644,
1899 &fnum);
1900 if (!NT_STATUS_IS_OK(status)) {
1901 printf("cli_posix_open of %s failed error %s\n",
1902 fname_real,
1903 nt_errstr(status));
1904 goto out;
1906 status = cli_close(cli_unix, fnum);
1907 if (!NT_STATUS_IS_OK(status)) {
1908 printf("cli_close failed %s\n", nt_errstr(status));
1909 goto out;
1911 fnum = (uint16_t)-1;
1913 /* Create symlink to real target. */
1914 status = cli_posix_symlink(cli_unix,
1915 fname_real,
1916 fname_real_symlink);
1917 if (!NT_STATUS_IS_OK(status)) {
1918 printf("cli_posix_symlink of %s -> %s failed error %s\n",
1919 fname_real_symlink,
1920 fname_real,
1921 nt_errstr(status));
1922 goto out;
1925 /* Now create symlink to non-existing target. */
1926 status = cli_posix_symlink(cli_unix,
1927 nonexist,
1928 nonexist_symlink);
1929 if (!NT_STATUS_IS_OK(status)) {
1930 printf("cli_posix_symlink of %s -> %s failed error %s\n",
1931 nonexist_symlink,
1932 nonexist,
1933 nt_errstr(status));
1934 goto out;
1937 for (i = 0; i < ARRAY_SIZE(posix_smb1_setpath_array); i++) {
1938 status = do_setpath(frame,
1939 cli_unix,
1940 fname_real_symlink,
1942 if (!NT_STATUS_IS_OK(status)) {
1943 goto out;
1945 status = do_setpath(frame,
1946 cli_unix,
1947 nonexist_symlink,
1949 if (!NT_STATUS_IS_OK(status)) {
1950 goto out;
1954 printf("POSIX-SYMLINK-SETPATHINFO test passed\n");
1955 correct = true;
1957 out:
1958 if (fnum != (uint16_t)-1) {
1959 cli_close(cli_unix, fnum);
1961 cli_posix_unlink(cli_unix, fname_real);
1962 cli_posix_unlink(cli_unix, fname_real_symlink);
1963 cli_posix_unlink(cli_unix, nonexist);
1964 cli_posix_unlink(cli_unix, nonexist_symlink);
1966 if (!torture_close_connection(cli_unix)) {
1967 correct = false;
1970 TALLOC_FREE(frame);
1971 return correct;