s3: smbtorture3: Add test_smb1_chkpath() DFS test to run_smb1_dfs_operations().
[Samba.git] / source3 / torture / test_smb1_dfs.c
blobbbaf7a5524e7dbd295f20976cc9865bbcca2d17d
1 /*
2 Unix SMB/CIFS implementation.
3 SMB1 DFS tests.
4 Copyright (C) Jeremy Allison 2022.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "torture/proto.h"
22 #include "client.h"
23 #include "trans2.h"
24 #include "../libcli/smb/smbXcli_base.h"
25 #include "libcli/security/security.h"
26 #include "libsmb/proto.h"
27 #include "auth/credentials/credentials.h"
28 #include "auth/gensec/gensec.h"
29 #include "auth_generic.h"
30 #include "../librpc/ndr/libndr.h"
31 #include "libsmb/clirap.h"
32 #include "async_smb.h"
33 #include "../lib/util/tevent_ntstatus.h"
34 #include "lib/util/time_basic.h"
36 extern fstring host, workgroup, share, password, username, myname;
37 extern struct cli_credentials *torture_creds;
40 * Open an SMB1 file readonly and return the create time.
42 static NTSTATUS get_smb1_crtime(struct cli_state *cli,
43 const char *pathname,
44 struct timespec *pcrtime)
46 NTSTATUS status;
47 uint16_t fnum = 0;
48 struct timespec crtime = {0};
51 * Open the file.
54 status = smb1cli_ntcreatex(cli->conn,
55 cli->timeout,
56 cli->smb1.pid,
57 cli->smb1.tcon,
58 cli->smb1.session,
59 pathname,
60 OPLOCK_NONE, /* CreatFlags */
61 0, /* RootDirectoryFid */
62 SEC_STD_SYNCHRONIZE|
63 SEC_FILE_READ_DATA|
64 SEC_FILE_READ_ATTRIBUTE, /* DesiredAccess */
65 0, /* AllocationSize */
66 FILE_ATTRIBUTE_NORMAL, /* FileAttributes */
67 FILE_SHARE_READ|
68 FILE_SHARE_WRITE|
69 FILE_SHARE_DELETE, /* ShareAccess */
70 FILE_OPEN, /* CreateDisposition */
71 0, /* CreateOptions */
72 2, /* ImpersonationLevel */
73 0, /* SecurityFlags */
74 &fnum);
75 if (!NT_STATUS_IS_OK(status)) {
76 return status;
80 * Get the create time. Note - we can use
81 * a higher-level cli_XXX function here
82 * for SMB1 as cli_qfileinfo_basic()
83 * doesn't use any pathnames, only fnums
84 * so it isn't affected by DFS pathnames.
86 status = cli_qfileinfo_basic(cli,
87 fnum,
88 NULL, /* attr */
89 NULL, /* size */
90 &crtime, /* create_time */
91 NULL, /* access_time */
92 NULL, /* write_time */
93 NULL, /* change_time */
94 NULL);
95 if (NT_STATUS_IS_OK(status)) {
96 *pcrtime = crtime;
99 (void)smb1cli_close(cli->conn,
100 cli->timeout,
101 cli->smb1.pid,
102 cli->smb1.tcon,
103 cli->smb1.session,
104 fnum,
105 0); /* last_modified */
106 return status;
110 * Check a crtime matches a given SMB1 path.
112 static bool smb1_crtime_matches(struct cli_state *cli,
113 const char *match_pathname,
114 struct timespec crtime_tomatch,
115 const char *test_pathname)
117 struct timespec test_crtime = { 0 };
118 NTSTATUS status;
119 bool equal = false;
121 status = get_smb1_crtime(cli,
122 test_pathname,
123 &test_crtime);
124 if (!NT_STATUS_IS_OK(status)) {
125 printf("%s: Failed to get crtime "
126 "for %s, (%s)\n",
127 __func__,
128 test_pathname,
129 nt_errstr(status));
130 return false;
132 equal = (timespec_compare(&test_crtime, &crtime_tomatch) == 0);
133 if (!equal) {
134 struct timeval_buf test_buf;
135 struct timeval_buf tomatch_buf;
136 printf("%s: crtime missmatch "
137 "%s:crtime_tomatch=%s, %s:test_crtime = %s\n",
138 __func__,
139 match_pathname,
140 timespec_string_buf(&crtime_tomatch,
141 true,
142 &tomatch_buf),
143 test_pathname,
144 timespec_string_buf(&test_crtime,
145 true,
146 &test_buf));
147 return false;
149 return true;
153 * Delete an SMB1 file on a DFS share.
155 static NTSTATUS smb1_dfs_delete(struct cli_state *cli,
156 const char *pathname)
158 NTSTATUS status;
159 uint16_t fnum = 0;
162 * Open the file.
165 status = smb1cli_ntcreatex(cli->conn,
166 cli->timeout,
167 cli->smb1.pid,
168 cli->smb1.tcon,
169 cli->smb1.session,
170 pathname,
171 OPLOCK_NONE, /* CreatFlags */
172 0, /* RootDirectoryFid */
173 SEC_STD_SYNCHRONIZE|
174 SEC_STD_DELETE, /* DesiredAccess */
175 0, /* AllocationSize */
176 FILE_ATTRIBUTE_NORMAL, /* FileAttributes */
177 FILE_SHARE_READ|
178 FILE_SHARE_WRITE|
179 FILE_SHARE_DELETE, /* ShareAccess */
180 FILE_OPEN, /* CreateDisposition */
181 0, /* CreateOptions */
182 2, /* ImpersonationLevel */
183 0, /* SecurityFlags */
184 &fnum);
185 if (!NT_STATUS_IS_OK(status)) {
186 return status;
190 * Set delete on close. Note - we can use
191 * a higher-level cli_XXX function here
192 * for SMB1 as cli_nt_delete_on_close()
193 * doesn't use any pathnames, only fnums
194 * so it isn't affected by DFS pathnames.
198 status = cli_nt_delete_on_close(cli, fnum, 1);
199 if (!NT_STATUS_IS_OK(status)) {
200 return status;
202 return smb1cli_close(cli->conn,
203 cli->timeout,
204 cli->smb1.pid,
205 cli->smb1.tcon,
206 cli->smb1.session,
207 fnum,
208 0); /* last_modified */
211 static void smb1_mv_done(struct tevent_req *subreq);
213 struct smb1_mv_state {
214 uint16_t vwv[1];
217 static struct tevent_req *smb1_mv_send(TALLOC_CTX *mem_ctx,
218 struct tevent_context *ev,
219 struct cli_state *cli,
220 const char *src_dfs_name,
221 const char *target_name)
223 uint8_t *bytes = NULL;
224 struct tevent_req *req = NULL;
225 struct tevent_req *subreq = NULL;
226 struct smb1_mv_state *state = NULL;
228 req = tevent_req_create(mem_ctx,
229 &state,
230 struct smb1_mv_state);
231 if (req == NULL) {
232 return NULL;
235 PUSH_LE_U16(state->vwv,
237 FILE_ATTRIBUTE_SYSTEM |
238 FILE_ATTRIBUTE_HIDDEN |
239 FILE_ATTRIBUTE_DIRECTORY);
241 bytes = talloc_array(state, uint8_t, 1);
242 if (tevent_req_nomem(bytes, req)) {
243 return tevent_req_post(req, ev);
245 bytes[0] = 4;
246 bytes = smb_bytes_push_str(bytes,
247 smbXcli_conn_use_unicode(cli->conn),
248 src_dfs_name,
249 strlen(src_dfs_name)+1,
250 NULL);
251 if (tevent_req_nomem(bytes, req)) {
252 return tevent_req_post(req, ev);
255 bytes = talloc_realloc(state,
256 bytes,
257 uint8_t,
258 talloc_get_size(bytes)+1);
259 if (tevent_req_nomem(bytes, req)) {
260 return tevent_req_post(req, ev);
263 bytes[talloc_get_size(bytes)-1] = 4;
264 bytes = smb_bytes_push_str(bytes,
265 smbXcli_conn_use_unicode(cli->conn),
266 target_name,
267 strlen(target_name)+1,
268 NULL);
269 if (tevent_req_nomem(bytes, req)) {
270 return tevent_req_post(req, ev);
273 subreq = cli_smb_send(state,
275 cli,
276 SMBmv,
277 0, /* additional_flags */
278 0, /* additional_flags2 */
280 state->vwv,
281 talloc_get_size(bytes),
282 bytes);
283 if (tevent_req_nomem(subreq, req)) {
284 return tevent_req_post(req, ev);
286 tevent_req_set_callback(subreq, smb1_mv_done, req);
287 return req;
290 static void smb1_mv_done(struct tevent_req *subreq)
292 NTSTATUS status = cli_smb_recv(subreq,
293 NULL,
294 NULL,
296 NULL,
297 NULL,
298 NULL,
299 NULL);
300 tevent_req_simple_finish_ntstatus(subreq,
301 status);
304 static NTSTATUS smb1_mv_recv(struct tevent_req *req)
306 return tevent_req_simple_recv_ntstatus(req);
310 * Rename an SMB1 file on a DFS share. SMBmv version.
312 static NTSTATUS smb1_mv(struct cli_state *cli,
313 const char *src_dfs_name,
314 const char *target_name)
316 TALLOC_CTX *frame = NULL;
317 struct tevent_context *ev;
318 struct tevent_req *req;
319 NTSTATUS status;
321 frame = talloc_stackframe();
323 ev = samba_tevent_context_init(frame);
324 if (ev == NULL) {
325 status = NT_STATUS_NO_MEMORY;
326 goto fail;
329 req = smb1_mv_send(frame,
331 cli,
332 src_dfs_name,
333 target_name);
334 if (req == NULL) {
335 status = NT_STATUS_NO_MEMORY;
336 goto fail;
339 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
340 goto fail;
343 status = smb1_mv_recv(req);
345 fail:
347 TALLOC_FREE(frame);
348 return status;
351 static bool test_smb1_mv(struct cli_state *cli,
352 const char *src_dfs_name)
354 struct timespec test_timespec = { 0 };
355 NTSTATUS status;
357 status = smb1_mv(cli,
358 src_dfs_name,
359 "BAD\\BAD\\renamed_file");
360 if (!NT_STATUS_IS_OK(status)) {
361 printf("%s:%d SMBmv of %s -> %s should succeed "
362 "got %s\n",
363 __FILE__,
364 __LINE__,
365 src_dfs_name,
366 "BAD\\BAD\\renamed_file",
367 nt_errstr(status));
368 return false;
371 /* Ensure we did rename. */
372 status = get_smb1_crtime(cli,
373 "BAD\\BAD\\renamed_file",
374 &test_timespec);
375 if (!NT_STATUS_IS_OK(status)) {
376 printf("%s:%d Failed to get crtime "
377 "for %s, (%s)\n",
378 __FILE__,
379 __LINE__,
380 "BAD\\BAD\\renamed_file",
381 nt_errstr(status));
382 return false;
385 /* Put it back. */
386 status = smb1_mv(cli,
387 "BAD\\BAD\\renamed_file",
388 src_dfs_name);
389 if (!NT_STATUS_IS_OK(status)) {
390 printf("%s:%d SMBmv of %s -> %s should succeed "
391 "got %s\n",
392 __FILE__,
393 __LINE__,
394 "BAD\\BAD\\renamed_file",
395 src_dfs_name,
396 nt_errstr(status));
397 return false;
400 /* Ensure we did put it back. */
401 status = get_smb1_crtime(cli,
402 src_dfs_name,
403 &test_timespec);
404 if (!NT_STATUS_IS_OK(status)) {
405 printf("%s:%d Failed to get crtime "
406 "for %s, (%s)\n",
407 __FILE__,
408 __LINE__,
409 src_dfs_name,
410 nt_errstr(status));
411 return false;
414 /* Try with a non-DFS name. */
415 status = smb1_mv(cli,
416 src_dfs_name,
417 "renamed_file");
418 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD)) {
419 /* Fails I think as target becomes "" on server. */
420 printf("%s:%d SMBmv of %s -> %s should get "
421 "NT_STATUS_OBJECT_PATH_SYNTAX_BAD got %s\n",
422 __FILE__,
423 __LINE__,
424 src_dfs_name,
425 "renamed_file",
426 nt_errstr(status));
427 return false;
430 /* Try with a non-DFS name. */
431 status = smb1_mv(cli,
432 src_dfs_name,
433 "BAD\\renamed_file");
434 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD)) {
435 /* Fails I think as target becomes "" on server. */
436 printf("%s:%d SMBmv of %s -> %s should get "
437 "NT_STATUS_OBJECT_PATH_SYNTAX_BAD got %s\n",
438 __FILE__,
439 __LINE__,
440 src_dfs_name,
441 "BAD\\renamed_file",
442 nt_errstr(status));
443 return false;
445 return true;
448 static void smb1_setpathinfo_done(struct tevent_req *subreq);
450 struct smb1_setpathinfo_state {
451 uint16_t setup;
452 uint8_t *param;
453 uint8_t *data;
456 static struct tevent_req *smb1_setpathinfo_send(TALLOC_CTX *mem_ctx,
457 struct tevent_context *ev,
458 struct cli_state *cli,
459 const char *src_dfs_name,
460 const char *target_name,
461 uint16_t info_level)
463 struct tevent_req *req = NULL;
464 struct tevent_req *subreq = NULL;
465 struct smb1_setpathinfo_state *state = NULL;
466 smb_ucs2_t *converted_str = NULL;
467 size_t converted_size_bytes = 0;
468 bool ok = false;
470 req = tevent_req_create(mem_ctx,
471 &state,
472 struct smb1_setpathinfo_state);
473 if (req == NULL) {
474 return NULL;
477 PUSH_LE_U16(&state->setup, 0, TRANSACT2_SETPATHINFO);
479 state->param = talloc_zero_array(state, uint8_t, 6);
480 if (tevent_req_nomem(state->param, req)) {
481 return tevent_req_post(req, ev);
483 PUSH_LE_U16(state->param, 0, info_level);
485 state->param = trans2_bytes_push_str(state->param,
486 smbXcli_conn_use_unicode(cli->conn),
487 src_dfs_name,
488 strlen(src_dfs_name)+1,
489 NULL);
490 if (tevent_req_nomem(state->param, req)) {
491 return tevent_req_post(req, ev);
494 ok = push_ucs2_talloc(state,
495 &converted_str,
496 target_name,
497 &converted_size_bytes);
498 if (!ok) {
499 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
500 return tevent_req_post(req, ev);
504 * W2K8 insists the dest name is not null
505 * terminated. Remove the last 2 zero bytes
506 * and reduce the name length.
509 if (converted_size_bytes < 2) {
510 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
511 return tevent_req_post(req, ev);
513 converted_size_bytes -= 2;
515 state->data = talloc_zero_array(state,
516 uint8_t,
517 12 + converted_size_bytes);
518 if (tevent_req_nomem(state->data, req)) {
519 return tevent_req_post(req, ev);
522 SIVAL(state->data, 8, converted_size_bytes);
523 memcpy(state->data + 12, converted_str, converted_size_bytes);
525 subreq = cli_trans_send(state, /* mem ctx. */
526 ev,/* event ctx. */
527 cli,/* cli_state. */
528 0,/* additional_flags2 */
529 SMBtrans2, /* cmd. */
530 NULL,/* pipe name. */
531 -1,/* fid. */
532 0,/* function. */
533 0,/* flags. */
534 &state->setup,/* setup. */
535 1,/* num setup uint16_t words. */
536 0,/* max returned setup. */
537 state->param,/* param. */
538 talloc_get_size(state->param),/* num param. */
539 2,/* max returned param. */
540 state->data,/* data. */
541 talloc_get_size(state->data),/* num data. */
542 0);/* max returned data. */
544 if (tevent_req_nomem(subreq, req)) {
545 return tevent_req_post(req, ev);
547 tevent_req_set_callback(subreq, smb1_setpathinfo_done, req);
548 return req;
551 static void smb1_setpathinfo_done(struct tevent_req *subreq)
553 NTSTATUS status = cli_trans_recv(subreq,
554 NULL,
555 NULL,
556 NULL,
558 NULL,
559 NULL,
561 NULL,
562 NULL,
564 NULL);
565 tevent_req_simple_finish_ntstatus(subreq,
566 status);
569 static NTSTATUS smb1_setpathinfo_recv(struct tevent_req *req)
571 return tevent_req_simple_recv_ntstatus(req);
575 * Rename or hardlink an SMB1 file on a DFS share. SMB1 setpathinfo
576 * (pathnames only) version.
578 static NTSTATUS smb1_setpathinfo(struct cli_state *cli,
579 const char *src_dfs_name,
580 const char *target_name,
581 uint16_t info_level)
583 TALLOC_CTX *frame = NULL;
584 struct tevent_context *ev;
585 struct tevent_req *req;
586 NTSTATUS status;
588 frame = talloc_stackframe();
590 ev = samba_tevent_context_init(frame);
591 if (ev == NULL) {
592 status = NT_STATUS_NO_MEMORY;
593 goto fail;
596 req = smb1_setpathinfo_send(frame,
598 cli,
599 src_dfs_name,
600 target_name,
601 info_level);
602 if (req == NULL) {
603 status = NT_STATUS_NO_MEMORY;
604 goto fail;
607 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
608 goto fail;
611 status = smb1_setpathinfo_recv(req);
613 fail:
615 TALLOC_FREE(frame);
616 return status;
619 static NTSTATUS smb1_setpathinfo_rename(struct cli_state *cli,
620 const char *src_dfs_name,
621 const char *target_name)
623 return smb1_setpathinfo(cli,
624 src_dfs_name,
625 target_name,
626 SMB_FILE_RENAME_INFORMATION);
629 static bool test_smb1_setpathinfo_rename(struct cli_state *cli,
630 const char *src_dfs_name)
632 struct timespec test_crtime = { 0 };
633 NTSTATUS status;
634 const char *putback_path = NULL;
637 * On Windows, setpathinfo rename where the target contains
638 * any directory separator returns STATUS_NOT_SUPPORTED.
640 * MS-SMB behavior note: <133> Section 3.3.5.10.6:
642 * "If the file name pointed to by the FileName parameter of the
643 * FILE_RENAME_INFORMATION structure contains a separator character,
644 * then the request fails with STATUS_NOT_SUPPORTED."
646 status = smb1_setpathinfo_rename(cli,
647 src_dfs_name,
648 "BAD\\BAD\\renamed_file");
649 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
650 printf("%s:%d SMB1 setpathinfo rename of %s -> %s should get "
651 "NT_STATUS_NOT_SUPPORTED got %s\n",
652 __FILE__,
653 __LINE__,
654 src_dfs_name,
655 "BAD\\BAD\\renamed_file",
656 nt_errstr(status));
657 return false;
660 /* Try with a non-DFS name. */
661 status = smb1_setpathinfo_rename(cli,
662 src_dfs_name,
663 "renamed_file");
664 if (!NT_STATUS_IS_OK(status)) {
665 printf("%s:%d SMB1 setpathinfo rename of %s -> %s "
666 "should succeed got %s\n",
667 __FILE__,
668 __LINE__,
669 src_dfs_name,
670 "renamed_file",
671 nt_errstr(status));
672 return false;
675 /* Ensure we did rename. */
676 status = get_smb1_crtime(cli,
677 "BAD\\BAD\\renamed_file",
678 &test_crtime);
679 if (!NT_STATUS_IS_OK(status)) {
680 printf("%s:%d Failed to get crtime "
681 "for %s, (%s)\n",
682 __FILE__,
683 __LINE__,
684 "BAD\\BAD\\renamed_file",
685 nt_errstr(status));
686 return false;
690 * To put it back we need to reverse the DFS-ness of src
691 * and destination paths.
693 putback_path = strrchr(src_dfs_name, '\\');
694 if (putback_path == NULL) {
695 printf("%s:%d non DFS path %s passed. Internal error\n",
696 __FILE__,
697 __LINE__,
698 src_dfs_name);
699 return false;
701 /* Walk past the last '\\' */
702 putback_path++;
704 /* Put it back. */
705 status = smb1_setpathinfo_rename(cli,
706 "BAD\\BAD\\renamed_file",
707 putback_path);
708 if (!NT_STATUS_IS_OK(status)) {
709 printf("%s:%d SMB1 setpathinfo rename of %s -> %s "
710 "should succeed got %s\n",
711 __FILE__,
712 __LINE__,
713 "BAD\\BAD\\renamed_file",
714 putback_path,
715 nt_errstr(status));
716 return false;
719 /* Ensure we did rename. */
720 status = get_smb1_crtime(cli,
721 src_dfs_name,
722 &test_crtime);
723 if (!NT_STATUS_IS_OK(status)) {
724 printf("%s:%d Failed to get crtime "
725 "for %s, (%s)\n",
726 __FILE__,
727 __LINE__,
728 src_dfs_name,
729 nt_errstr(status));
730 return false;
733 return true;
736 static NTSTATUS smb1_setpathinfo_hardlink(struct cli_state *cli,
737 const char *src_dfs_name,
738 const char *target_name)
740 return smb1_setpathinfo(cli,
741 src_dfs_name,
742 target_name,
743 SMB_FILE_LINK_INFORMATION);
746 static bool test_smb1_setpathinfo_hardlink(struct cli_state *cli,
747 const char *src_dfs_name)
749 NTSTATUS status;
752 * On Windows, setpathinfo rename where the target contains
753 * any directory separator returns STATUS_NOT_SUPPORTED.
755 * MS-SMB behavior note: <133> Section 3.3.5.10.6:
757 * "If the file name pointed to by the FileName parameter of the
758 * FILE_RENAME_INFORMATION structure contains a separator character,
759 * then the request fails with STATUS_NOT_SUPPORTED."
761 * setpathinfo info level SMB_FILE_LINK_INFORMATION
762 * seems to do the same, but this could be an artifact
763 * of the Windows version tested (Win2K8). I will
764 * revisit this when I'm able to test against
765 * a later Windows version with a DFS server.
767 status = smb1_setpathinfo_hardlink(cli,
768 src_dfs_name,
769 "BAD\\BAD\\hlink");
770 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
771 printf("%s:%d SMB1 setpathinfo hardlink of %s -> %s should get "
772 "NT_STATUS_NOT_SUPPORTED got %s\n",
773 __FILE__,
774 __LINE__,
775 src_dfs_name,
776 "BAD\\BAD\\hlink",
777 nt_errstr(status));
778 return false;
781 /* Try with a non-DFS name. */
783 * At least on Windows 2008 this also fails with
784 * NT_STATUS_NOT_SUPPORTED, leading me to believe
785 * setting hardlinks is only supported via NTrename
786 * in SMB1.
788 status = smb1_setpathinfo_hardlink(cli,
789 src_dfs_name,
790 "hlink");
791 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
792 printf("%s:%d SMB1 setpathinfo hardlink of %s -> %s should get "
793 "NT_STATUS_NOT_SUPPORTED got %s\n",
794 __FILE__,
795 __LINE__,
796 src_dfs_name,
797 "hlink",
798 nt_errstr(status));
799 return false;
801 return true;
804 static void smb1_ntrename_done(struct tevent_req *subreq);
806 struct smb1_ntrename_state {
807 uint16_t vwv[4];
810 static struct tevent_req *smb1_ntrename_send(TALLOC_CTX *mem_ctx,
811 struct tevent_context *ev,
812 struct cli_state *cli,
813 const char *src_dfs_name,
814 const char *target_name,
815 uint16_t rename_flag)
817 struct tevent_req *req = NULL;
818 struct tevent_req *subreq = NULL;
819 struct smb1_ntrename_state *state = NULL;
820 uint8_t *bytes = NULL;
822 req = tevent_req_create(mem_ctx,
823 &state,
824 struct smb1_ntrename_state);
825 if (req == NULL) {
826 return NULL;
829 PUSH_LE_U16(state->vwv,
831 FILE_ATTRIBUTE_SYSTEM |
832 FILE_ATTRIBUTE_HIDDEN |
833 FILE_ATTRIBUTE_DIRECTORY);
834 PUSH_LE_U16(state->vwv, 2, rename_flag);
836 bytes = talloc_array(state, uint8_t, 1);
837 if (tevent_req_nomem(bytes, req)) {
838 return tevent_req_post(req, ev);
841 bytes[0] = 4;
842 bytes = smb_bytes_push_str(bytes,
843 smbXcli_conn_use_unicode(cli->conn),
844 src_dfs_name,
845 strlen(src_dfs_name)+1,
846 NULL);
847 if (tevent_req_nomem(bytes, req)) {
848 return tevent_req_post(req, ev);
850 bytes = talloc_realloc(state,
851 bytes,
852 uint8_t,
853 talloc_get_size(bytes)+1);
854 if (tevent_req_nomem(bytes, req)) {
855 return tevent_req_post(req, ev);
858 bytes[talloc_get_size(bytes)-1] = 4;
859 bytes = smb_bytes_push_str(bytes,
860 smbXcli_conn_use_unicode(cli->conn),
861 target_name,
862 strlen(target_name)+1,
863 NULL);
864 if (tevent_req_nomem(bytes, req)) {
865 return tevent_req_post(req, ev);
868 subreq = cli_smb_send(state,
870 cli,
871 SMBntrename,
872 0, /* additional_flags */
873 0, /* additional_flags2 */
875 state->vwv,
876 talloc_get_size(bytes),
877 bytes);
878 if (tevent_req_nomem(subreq, req)) {
879 return tevent_req_post(req, ev);
881 tevent_req_set_callback(subreq, smb1_ntrename_done, req);
882 return req;
885 static void smb1_ntrename_done(struct tevent_req *subreq)
887 NTSTATUS status = cli_smb_recv(subreq,
888 NULL,
889 NULL,
891 NULL,
892 NULL,
893 NULL,
894 NULL);
895 tevent_req_simple_finish_ntstatus(subreq, status);
898 static NTSTATUS smb1_ntrename_recv(struct tevent_req *req)
900 return tevent_req_simple_recv_ntstatus(req);
904 * Rename or hardlink an SMB1 file on a DFS share. SMB1 ntrename version.
905 * (pathnames only).
907 static NTSTATUS smb1_ntrename(struct cli_state *cli,
908 const char *src_dfs_name,
909 const char *target_name,
910 uint16_t rename_flag)
912 TALLOC_CTX *frame = NULL;
913 struct tevent_context *ev;
914 struct tevent_req *req;
915 NTSTATUS status;
917 frame = talloc_stackframe();
919 ev = samba_tevent_context_init(frame);
920 if (ev == NULL) {
921 status = NT_STATUS_NO_MEMORY;
922 goto fail;
925 req = smb1_ntrename_send(frame,
927 cli,
928 src_dfs_name,
929 target_name,
930 rename_flag);
931 if (req == NULL) {
932 status = NT_STATUS_NO_MEMORY;
933 goto fail;
936 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
937 goto fail;
940 status = smb1_ntrename_recv(req);
942 fail:
944 TALLOC_FREE(frame);
945 return status;
948 * Rename an SMB1 file on a DFS share. SMB1 ntrename version.
950 static NTSTATUS smb1_ntrename_rename(struct cli_state *cli,
951 const char *src_dfs_name,
952 const char *target_name)
954 return smb1_ntrename(cli,
955 src_dfs_name,
956 target_name,
957 RENAME_FLAG_RENAME);
961 static bool test_smb1_ntrename_rename(struct cli_state *cli,
962 const char *src_dfs_name)
964 struct timespec test_crtime = { 0 };
965 NTSTATUS status;
967 /* Try with a non-DFS name. */
968 status = smb1_ntrename_rename(cli,
969 src_dfs_name,
970 "renamed_file");
971 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD)) {
972 /* Fails I think as target becomes "" on server. */
973 printf("%s:%d SMB1 ntrename rename of %s -> %s should get "
974 "NT_STATUS_OBJECT_PATH_SYNTAX_BAD got %s\n",
975 __FILE__,
976 __LINE__,
977 src_dfs_name,
978 "renamed_file",
979 nt_errstr(status));
980 return false;
983 status = smb1_ntrename_rename(cli,
984 src_dfs_name,
985 "BAD\\BAD\\renamed_file");
986 if (!NT_STATUS_IS_OK(status)) {
987 printf("%s:%d SMB1 ntrename rename of %s -> %s should "
988 "succeed got %s\n",
989 __FILE__,
990 __LINE__,
991 src_dfs_name,
992 "BAD\\BAD\\renamed_file",
993 nt_errstr(status));
994 return false;
997 /* Ensure we did rename. */
998 status = get_smb1_crtime(cli,
999 "BAD\\BAD\\renamed_file",
1000 &test_crtime);
1001 if (!NT_STATUS_IS_OK(status)) {
1002 printf("%s:%d Failed to get crtime "
1003 "for %s, (%s)\n",
1004 __FILE__,
1005 __LINE__,
1006 "BAD\\BAD\\renamed_file",
1007 nt_errstr(status));
1008 return false;
1011 /* Put it back. */
1012 status = smb1_ntrename_rename(cli,
1013 "BAD\\BAD\\renamed_file",
1014 src_dfs_name);
1015 if (!NT_STATUS_IS_OK(status)) {
1016 printf("%s:%d SMB1 ntrename rename of %s -> %s "
1017 "should succeed got %s\n",
1018 __FILE__,
1019 __LINE__,
1020 "BAD\\BAD\\renamed_file",
1021 src_dfs_name,
1022 nt_errstr(status));
1023 return false;
1026 /* Ensure we did rename. */
1027 status = get_smb1_crtime(cli,
1028 src_dfs_name,
1029 &test_crtime);
1030 if (!NT_STATUS_IS_OK(status)) {
1031 printf("%s:%d Failed to get crtime "
1032 "for %s, (%s)\n",
1033 __FILE__,
1034 __LINE__,
1035 src_dfs_name,
1036 nt_errstr(status));
1037 return false;
1040 return true;
1044 * Hard link an SMB1 file on a DFS share. SMB1 ntrename version.
1046 static NTSTATUS smb1_ntrename_hardlink(struct cli_state *cli,
1047 const char *src_dfs_name,
1048 const char *target_name)
1050 return smb1_ntrename(cli,
1051 src_dfs_name,
1052 target_name,
1053 RENAME_FLAG_HARD_LINK);
1056 static bool test_smb1_ntrename_hardlink(struct cli_state *cli,
1057 const char *src_dfs_name)
1059 struct timespec test_crtime = { 0 };
1060 NTSTATUS status;
1061 bool retval = false;
1063 /* Try with a non-DFS name. */
1064 status = smb1_ntrename_hardlink(cli,
1065 src_dfs_name,
1066 "hlink");
1067 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD)) {
1068 /* Fails I think as target becomes "" on server. */
1069 printf("%s:%d SMB1 ntrename of %s -> %s should get "
1070 "NT_STATUS_OBJECT_PATH_SYNTAX_BAD got %s\n",
1071 __FILE__,
1072 __LINE__,
1073 src_dfs_name,
1074 "hlink",
1075 nt_errstr(status));
1076 return false;
1079 status = smb1_ntrename_hardlink(cli,
1080 src_dfs_name,
1081 "BAD\\BAD\\hlink");
1082 if (!NT_STATUS_IS_OK(status)) {
1083 printf("%s:%d SMB1 ntrename hardlink of %s -> %s "
1084 "should succeed got %s\n",
1085 __FILE__,
1086 __LINE__,
1087 src_dfs_name,
1088 "BAD\\BAD\\hlink",
1089 nt_errstr(status));
1090 goto out;
1093 /* Ensure we did hardlink. */
1094 status = get_smb1_crtime(cli,
1095 "BAD\\BAD\\hlink",
1096 &test_crtime);
1097 if (!NT_STATUS_IS_OK(status)) {
1098 printf("%s:%d Failed to get crtime "
1099 "for %s, (%s)\n",
1100 __FILE__,
1101 __LINE__,
1102 "BAD\\BAD\\hlink",
1103 nt_errstr(status));
1104 goto out;
1107 retval = smb1_crtime_matches(cli,
1108 "BAD\\BAD\\hlink",
1109 test_crtime,
1110 src_dfs_name);
1111 if (!retval) {
1112 printf("%s:%d smb1_crtime_matches failed for "
1113 "%s %s\n",
1114 __FILE__,
1115 __LINE__,
1116 src_dfs_name,
1117 "BAD\\BAD\\hlink");
1118 goto out;
1121 out:
1123 /* Remove the hardlink to clean up. */
1124 (void)smb1_dfs_delete(cli, "BAD\\BAD\\hlink");
1125 return retval;
1128 static void smb1_setfileinfo_done(struct tevent_req *subreq);
1130 struct smb1_setfileinfo_state {
1131 uint16_t setup;
1132 uint8_t param[6];
1133 uint8_t *data;
1136 static struct tevent_req *smb1_setfileinfo_send(TALLOC_CTX *mem_ctx,
1137 struct tevent_context *ev,
1138 struct cli_state *cli,
1139 uint16_t fnum,
1140 const char *target_name,
1141 uint16_t info_level)
1143 struct tevent_req *req = NULL;
1144 struct tevent_req *subreq = NULL;
1145 struct smb1_setfileinfo_state *state = NULL;
1146 smb_ucs2_t *converted_str = NULL;
1147 size_t converted_size_bytes = 0;
1148 bool ok = false;
1150 req = tevent_req_create(mem_ctx,
1151 &state,
1152 struct smb1_setfileinfo_state);
1153 if (req == NULL) {
1154 return NULL;
1157 PUSH_LE_U16(&state->setup, 0, TRANSACT2_SETPATHINFO);
1159 PUSH_LE_U16(state->param, 0, fnum);
1160 PUSH_LE_U16(state->param, 2, info_level);
1162 ok = push_ucs2_talloc(state,
1163 &converted_str,
1164 target_name,
1165 &converted_size_bytes);
1166 if (!ok) {
1167 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1168 return tevent_req_post(req, ev);
1172 * W2K8 insists the dest name is not null
1173 * terminated. Remove the last 2 zero bytes
1174 * and reduce the name length.
1177 if (converted_size_bytes < 2) {
1178 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1179 return tevent_req_post(req, ev);
1181 converted_size_bytes -= 2;
1183 state->data = talloc_zero_array(state,
1184 uint8_t,
1185 12 + converted_size_bytes);
1186 if (tevent_req_nomem(state->data, req)) {
1187 return tevent_req_post(req, ev);
1190 SIVAL(state->data, 8, converted_size_bytes);
1191 memcpy(state->data + 12, converted_str, converted_size_bytes);
1193 subreq = cli_trans_send(state, /* mem ctx. */
1194 ev,/* event ctx. */
1195 cli,/* cli_state. */
1196 0,/* additional_flags2 */
1197 SMBtrans2, /* cmd. */
1198 NULL,/* pipe name. */
1199 -1,/* fid. */
1200 0,/* function. */
1201 0,/* flags. */
1202 &state->setup,/* setup. */
1203 1,/* num setup uint16_t words. */
1204 0,/* max returned setup. */
1205 state->param,/* param. */
1206 6,/* num param. */
1207 2,/* max returned param. */
1208 state->data,/* data. */
1209 talloc_get_size(state->data),/* num data. */
1210 0);/* max returned data. */
1212 if (tevent_req_nomem(subreq, req)) {
1213 return tevent_req_post(req, ev);
1215 tevent_req_set_callback(subreq, smb1_setfileinfo_done, req);
1216 return req;
1219 static void smb1_setfileinfo_done(struct tevent_req *subreq)
1221 NTSTATUS status = cli_trans_recv(subreq,
1222 NULL,
1223 NULL,
1224 NULL,
1226 NULL,
1227 NULL,
1229 NULL,
1230 NULL,
1232 NULL);
1233 tevent_req_simple_finish_ntstatus(subreq,
1234 status);
1237 static NTSTATUS smb1_setfileinfo_recv(struct tevent_req *req)
1239 return tevent_req_simple_recv_ntstatus(req);
1243 * Rename or hardlink an SMB1 file on a DFS share.
1244 * setfileinfo (file handle + target pathname) version.
1246 static NTSTATUS smb1_setfileinfo(struct cli_state *cli,
1247 uint16_t fnum,
1248 const char *target_name,
1249 uint16_t info_level)
1251 TALLOC_CTX *frame = NULL;
1252 struct tevent_context *ev;
1253 struct tevent_req *req;
1254 NTSTATUS status;
1256 frame = talloc_stackframe();
1258 ev = samba_tevent_context_init(frame);
1259 if (ev == NULL) {
1260 status = NT_STATUS_NO_MEMORY;
1261 goto fail;
1264 req = smb1_setfileinfo_send(frame,
1266 cli,
1267 fnum,
1268 target_name,
1269 info_level);
1270 if (req == NULL) {
1271 status = NT_STATUS_NO_MEMORY;
1272 goto fail;
1275 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1276 goto fail;
1279 status = smb1_setfileinfo_recv(req);
1281 fail:
1283 TALLOC_FREE(frame);
1284 return status;
1287 static NTSTATUS smb1_setfileinfo_rename(struct cli_state *cli,
1288 uint16_t fnum,
1289 const char *target_name)
1291 return smb1_setfileinfo(cli,
1292 fnum,
1293 target_name,
1294 SMB_FILE_RENAME_INFORMATION);
1298 * On Windows, rename using a file handle as source
1299 * is not supported.
1302 static bool test_smb1_setfileinfo_rename(struct cli_state *cli,
1303 const char *src_dfs_name)
1305 uint16_t fnum = (uint16_t)-1;
1306 NTSTATUS status;
1307 bool retval = false;
1309 /* First open the source file. */
1310 status = smb1cli_ntcreatex(cli->conn,
1311 cli->timeout,
1312 cli->smb1.pid,
1313 cli->smb1.tcon,
1314 cli->smb1.session,
1315 src_dfs_name,
1316 OPLOCK_NONE, /* CreatFlags */
1317 0, /* RootDirectoryFid */
1318 SEC_STD_SYNCHRONIZE|
1319 SEC_STD_DELETE, /* DesiredAccess */
1320 0, /* AllocationSize */
1321 FILE_ATTRIBUTE_NORMAL, /* FileAttributes */
1322 FILE_SHARE_READ|
1323 FILE_SHARE_WRITE|
1324 FILE_SHARE_DELETE, /* ShareAccess */
1325 FILE_OPEN, /* CreateDisposition */
1326 0, /* CreateOptions */
1327 2, /* ImpersonationLevel */
1328 0, /* SecurityFlags */
1329 &fnum);
1330 if (!NT_STATUS_IS_OK(status)) {
1331 printf("%s:%d failed to open %s, %s\n",
1332 __FILE__,
1333 __LINE__,
1334 src_dfs_name,
1335 nt_errstr(status));
1336 goto out;
1340 * On Windows rename given a file handle returns
1341 * NT_STATUS_UNSUCCESSFUL (not documented in MS-SMB).
1344 status = smb1_setfileinfo_rename(cli,
1345 fnum,
1346 "BAD\\BAD\\renamed_file");
1347 if (!NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1348 printf("%s:%d SMB1 setfileinfo rename of %s -> %s should get "
1349 "NT_STATUS_UNSUCCESSFUL got %s\n",
1350 __FILE__,
1351 __LINE__,
1352 src_dfs_name,
1353 "BAD\\BAD\\hlink",
1354 nt_errstr(status));
1355 goto out;
1358 /* Try with a non-DFS name - still gets NT_STATUS_UNSUCCESSFUL. */
1359 status = smb1_setfileinfo_rename(cli,
1360 fnum,
1361 "renamed_file");
1362 if (!NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1363 printf("%s:%d SMB1 setfileinfo rename of %s -> %s should get "
1364 "NT_STATUS_UNSUCCESSFUL got %s\n",
1365 __FILE__,
1366 __LINE__,
1367 src_dfs_name,
1368 "hlink",
1369 nt_errstr(status));
1370 goto out;
1373 retval = true;
1375 out:
1377 if (fnum != (uint16_t)-1) {
1378 (void)smb1cli_close(cli->conn,
1379 cli->timeout,
1380 cli->smb1.pid,
1381 cli->smb1.tcon,
1382 cli->smb1.session,
1383 fnum,
1384 0); /* last_modified */
1387 (void)smb1_dfs_delete(cli, "BAD\\BAD\\renamed_file");
1388 return retval;
1392 static NTSTATUS smb1_setfileinfo_hardlink(struct cli_state *cli,
1393 uint16_t fnum,
1394 const char *target_name)
1396 return smb1_setfileinfo(cli,
1397 fnum,
1398 target_name,
1399 SMB_FILE_LINK_INFORMATION);
1403 * On Windows, hardlink using a file handle as source
1404 * is not supported.
1407 static bool test_smb1_setfileinfo_hardlink(struct cli_state *cli,
1408 const char *src_dfs_name)
1410 uint16_t fnum = (uint16_t)-1;
1411 NTSTATUS status;
1412 bool retval = false;
1414 /* First open the source file. */
1415 status = smb1cli_ntcreatex(cli->conn,
1416 cli->timeout,
1417 cli->smb1.pid,
1418 cli->smb1.tcon,
1419 cli->smb1.session,
1420 src_dfs_name,
1421 OPLOCK_NONE, /* CreatFlags */
1422 0, /* RootDirectoryFid */
1423 SEC_STD_SYNCHRONIZE|
1424 SEC_RIGHTS_FILE_READ, /* DesiredAccess */
1425 0, /* AllocationSize */
1426 FILE_ATTRIBUTE_NORMAL, /* FileAttributes */
1427 FILE_SHARE_READ|
1428 FILE_SHARE_WRITE|
1429 FILE_SHARE_DELETE, /* ShareAccess */
1430 FILE_OPEN, /* CreateDisposition */
1431 0, /* CreateOptions */
1432 2, /* ImpersonationLevel */
1433 0, /* SecurityFlags */
1434 &fnum);
1435 if (!NT_STATUS_IS_OK(status)) {
1436 printf("%s:%d failed to open %s, %s\n",
1437 __FILE__,
1438 __LINE__,
1439 src_dfs_name,
1440 nt_errstr(status));
1441 goto out;
1445 * On Windows hardlink given a file handle returns
1446 * NT_STATUS_UNSUCCESSFUL (not documented in MS-SMB).
1449 status = smb1_setfileinfo_hardlink(cli,
1450 fnum,
1451 "BAD\\BAD\\hlink");
1452 if (!NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1453 printf("%s:%d SMB1 setfileinfo hardlink of %s -> %s should get "
1454 "NT_STATUS_UNSUCCESSFUL got %s\n",
1455 __FILE__,
1456 __LINE__,
1457 src_dfs_name,
1458 "BAD\\BAD\\hlink",
1459 nt_errstr(status));
1460 goto out;
1463 /* Try with a non-DFS name - still gets NT_STATUS_UNSUCCESSFUL. */
1464 status = smb1_setfileinfo_hardlink(cli,
1465 fnum,
1466 "hlink");
1467 if (!NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1468 printf("%s:%d SMB1 setfileinfo hardlink of %s -> %s should get "
1469 "NT_STATUS_UNSUCCESSFUL got %s\n",
1470 __FILE__,
1471 __LINE__,
1472 src_dfs_name,
1473 "hlink",
1474 nt_errstr(status));
1475 goto out;
1478 retval = true;
1480 out:
1482 if (fnum != (uint16_t)-1) {
1483 (void)smb1cli_close(cli->conn,
1484 cli->timeout,
1485 cli->smb1.pid,
1486 cli->smb1.tcon,
1487 cli->smb1.session,
1488 fnum,
1489 0); /* last_modified */
1492 (void)smb1_dfs_delete(cli, "BAD\\BAD\\hlink");
1493 return retval;
1497 * According to:
1499 * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/dc9978d7-6299-4c5a-a22d-a039cdc716ea
1501 * (Characters " \ / [ ] : | < > + = ; , * ?,
1502 * and control characters in range 0x00 through
1503 * 0x1F, inclusive, are illegal in a share name)
1505 * But Windows server only checks in DFS sharenames ':'. All other
1506 * share names are allowed.
1509 static bool test_smb1_dfs_sharenames(struct cli_state *cli,
1510 const char *dfs_root_share_name,
1511 struct timespec root_crtime)
1513 char test_path[20];
1514 const char *test_str = "/[]:|<>+=;,*?";
1515 const char *p;
1516 unsigned int i;
1517 bool crtime_matched = false;
1519 /* Setup template pathname. */
1520 memcpy(test_path, "\\SERVER\\X", 10);
1522 /* Test invalid control characters. */
1523 for (i = 1; i < 0x20; i++) {
1524 test_path[8] = i;
1525 crtime_matched = smb1_crtime_matches(cli,
1526 dfs_root_share_name,
1527 root_crtime,
1528 test_path);
1529 if (!crtime_matched) {
1530 return false;
1534 /* Test explicit invalid characters. */
1535 for (p = test_str; *p != '\0'; p++) {
1536 test_path[8] = *p;
1537 if (*p == ':') {
1539 * Only ':' is treated as an INVALID sharename
1540 * for a DFS SERVER\\SHARE path.
1542 struct timespec test_crtime = { 0 };
1543 NTSTATUS status = get_smb1_crtime(cli,
1544 test_path,
1545 &test_crtime);
1546 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_INVALID)) {
1547 printf("%s:%d Open of %s should get "
1548 "NT_STATUS_OBJECT_NAME_INVALID, got %s\n",
1549 __FILE__,
1550 __LINE__,
1551 test_path,
1552 nt_errstr(status));
1553 return false;
1555 } else {
1556 crtime_matched = smb1_crtime_matches(cli,
1557 dfs_root_share_name,
1558 root_crtime,
1559 test_path);
1560 if (!crtime_matched) {
1561 return false;
1565 return true;
1569 * "Raw" test of SMB1 paths to a DFS share.
1570 * We must (mostly) use the lower level smb1cli_XXXX() interfaces,
1571 * not the cli_XXX() ones here as the ultimate goal is to fix our
1572 * cli_XXX() interfaces to work transparently over DFS.
1574 * So here, we're testing the server code, not the client code.
1576 * Passes cleanly against Windows.
1579 bool run_smb1_dfs_paths(int dummy)
1581 struct cli_state *cli = NULL;
1582 NTSTATUS status;
1583 bool dfs_supported = false;
1584 char *dfs_root_share_name = NULL;
1585 struct timespec root_crtime = { 0 };
1586 struct timespec test_crtime = { 0 };
1587 bool crtime_matched = false;
1588 bool retval = false;
1589 bool ok = false;
1590 bool equal = false;
1591 unsigned int i;
1592 uint16_t fnum = (uint16_t)-1;
1594 printf("Starting SMB1-DFS-PATHS\n");
1596 if (!torture_init_connection(&cli)) {
1597 return false;
1600 if (!torture_open_connection(&cli, 0)) {
1601 return false;
1604 /* Ensure this is a DFS share. */
1605 dfs_supported = smbXcli_conn_dfs_supported(cli->conn);
1606 if (!dfs_supported) {
1607 printf("Server %s does not support DFS\n",
1608 smbXcli_conn_remote_name(cli->conn));
1609 return false;
1611 dfs_supported = smbXcli_tcon_is_dfs_share(cli->smb1.tcon);
1612 if (!dfs_supported) {
1613 printf("Share %s does not support DFS\n",
1614 cli->share);
1615 return false;
1618 /* Start with an empty share. */
1619 (void)smb1_dfs_delete(cli, "BAD\\BAD\\BAD");
1620 (void)smb1_dfs_delete(cli, "BAD\\BAD\\file");
1621 (void)smb1_dfs_delete(cli, "BAD\\BAD\\renamed_file");
1622 (void)smb1_dfs_delete(cli, "BAD\\BAD\\hlink");
1625 * Create the "official" DFS share root name.
1627 dfs_root_share_name = talloc_asprintf(talloc_tos(),
1628 "\\%s\\%s",
1629 smbXcli_conn_remote_name(cli->conn),
1630 cli->share);
1631 if (dfs_root_share_name == NULL) {
1632 printf("Out of memory\n");
1633 return false;
1636 /* Get the share root crtime. */
1637 status = get_smb1_crtime(cli,
1638 dfs_root_share_name,
1639 &root_crtime);
1640 if (!NT_STATUS_IS_OK(status)) {
1641 printf("%s:%d Failed to get crtime for share root %s, (%s)\n",
1642 __FILE__,
1643 __LINE__,
1644 dfs_root_share_name,
1645 nt_errstr(status));
1646 return false;
1650 * Test the Windows algorithm for parsing DFS names.
1653 * A single "SERVER" element should open and match the share root.
1655 crtime_matched = smb1_crtime_matches(cli,
1656 dfs_root_share_name,
1657 root_crtime,
1658 smbXcli_conn_remote_name(cli->conn));
1659 if (!crtime_matched) {
1660 printf("%s:%d Failed to match crtime for %s\n",
1661 __FILE__,
1662 __LINE__,
1663 smbXcli_conn_remote_name(cli->conn));
1664 return false;
1667 /* An "" (empty) server name should open and match the share root. */
1668 crtime_matched = smb1_crtime_matches(cli,
1669 dfs_root_share_name,
1670 root_crtime,
1671 "");
1672 if (!crtime_matched) {
1673 printf("%s:%d Failed to match crtime for %s\n",
1674 __FILE__,
1675 __LINE__,
1676 "");
1677 return false;
1681 * For SMB1 the server just strips off any number of leading '\\'
1682 * characters. Show this is the case.
1684 for (i = 0; i < 10; i++) {
1685 char leading_backslash_name[20];
1686 leading_backslash_name[i] = '\\';
1687 memcpy(&leading_backslash_name[i+1],
1688 "SERVER",
1689 strlen("SERVER")+1);
1691 crtime_matched = smb1_crtime_matches(cli,
1692 dfs_root_share_name,
1693 root_crtime,
1694 leading_backslash_name);
1695 if (!crtime_matched) {
1696 printf("%s:%d Failed to match crtime for %s\n",
1697 __FILE__,
1698 __LINE__,
1699 leading_backslash_name);
1700 return false;
1704 /* A "BAD" server name should open and match the share root. */
1705 crtime_matched = smb1_crtime_matches(cli,
1706 dfs_root_share_name,
1707 root_crtime,
1708 "BAD");
1709 if (!crtime_matched) {
1710 printf("%s:%d Failed to match crtime for %s\n",
1711 __FILE__,
1712 __LINE__,
1713 "BAD");
1714 return false;
1717 * A "BAD\\BAD" server and share name should open
1718 * and match the share root.
1720 crtime_matched = smb1_crtime_matches(cli,
1721 dfs_root_share_name,
1722 root_crtime,
1723 "BAD\\BAD");
1724 if (!crtime_matched) {
1725 printf("%s:%d Failed to match crtime for %s\n",
1726 __FILE__,
1727 __LINE__,
1728 "BAD\\BAD");
1729 return false;
1732 * Trying to open "BAD\\BAD\\BAD" should get
1733 * NT_STATUS_OBJECT_NAME_NOT_FOUND.
1735 status = get_smb1_crtime(cli,
1736 "BAD\\BAD\\BAD",
1737 &test_crtime);
1738 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1739 printf("%s:%d Open of %s should get "
1740 "STATUS_OBJECT_NAME_NOT_FOUND, got %s\n",
1741 __FILE__,
1742 __LINE__,
1743 "BAD\\BAD\\BAD",
1744 nt_errstr(status));
1745 return false;
1748 * Trying to open "BAD\\BAD\\BAD\\BAD" should get
1749 * NT_STATUS_OBJECT_PATH_NOT_FOUND.
1751 status = get_smb1_crtime(cli,
1752 "BAD\\BAD\\BAD\\BAD",
1753 &test_crtime);
1754 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
1755 printf("%s:%d Open of %s should get "
1756 "STATUS_OBJECT_NAME_NOT_FOUND, got %s\n",
1757 __FILE__,
1758 __LINE__,
1759 "BAD\\BAD\\BAD\\BAD",
1760 nt_errstr(status));
1761 return false;
1764 * Test for invalid pathname characters in the servername.
1765 * They are ignored, and it still opens the share root.
1767 crtime_matched = smb1_crtime_matches(cli,
1768 dfs_root_share_name,
1769 root_crtime,
1770 "::::");
1771 if (!crtime_matched) {
1772 printf("%s:%d Failed to match crtime for %s\n",
1773 __FILE__,
1774 __LINE__,
1775 "::::");
1776 return false;
1780 * Test for invalid pathname characters in the sharename.
1781 * Invalid sharename characters should still be flagged as
1782 * NT_STATUS_OBJECT_NAME_INVALID. It turns out only ':'
1783 * is considered an invalid sharename character.
1785 ok = test_smb1_dfs_sharenames(cli,
1786 dfs_root_share_name,
1787 root_crtime);
1788 if (!ok) {
1789 return false;
1792 status = smb1cli_ntcreatex(cli->conn,
1793 cli->timeout,
1794 cli->smb1.pid,
1795 cli->smb1.tcon,
1796 cli->smb1.session,
1797 "BAD\\BAD\\file",
1798 OPLOCK_NONE, /* CreatFlags */
1799 0, /* RootDirectoryFid */
1800 SEC_STD_SYNCHRONIZE|
1801 SEC_STD_DELETE |
1802 SEC_FILE_READ_DATA|
1803 SEC_FILE_READ_ATTRIBUTE, /* DesiredAccess */
1804 0, /* AllocationSize */
1805 FILE_ATTRIBUTE_NORMAL, /* FileAttributes */
1806 FILE_SHARE_READ|
1807 FILE_SHARE_WRITE|
1808 FILE_SHARE_DELETE, /* ShareAccess */
1809 FILE_CREATE, /* CreateDisposition */
1810 0, /* CreateOptions */
1811 2, /* ImpersonationLevel */
1812 0, /* SecurityFlags */
1813 &fnum);
1814 if (!NT_STATUS_IS_OK(status)) {
1815 printf("%s:%d smb1cli_ntcreatex on %s returned %s\n",
1816 __FILE__,
1817 __LINE__,
1818 "BAD\\BAD\\file",
1819 nt_errstr(status));
1820 return false;
1823 /* Close "file" handle. */
1824 (void)smb1cli_close(cli->conn,
1825 cli->timeout,
1826 cli->smb1.pid,
1827 cli->smb1.tcon,
1828 cli->smb1.session,
1829 fnum,
1830 0); /* last_modified */
1831 fnum = (uint16_t)-1;
1834 * Trying to open "BAD\\BAD\\file" should now get
1835 * a valid crtime.
1837 status = get_smb1_crtime(cli,
1838 "BAD\\BAD\\file",
1839 &test_crtime);
1840 if (!NT_STATUS_IS_OK(status)) {
1841 printf("%s:%d Open of %s should succeed "
1842 "got %s\n",
1843 __FILE__,
1844 __LINE__,
1845 "BAD\\BAD\\file",
1846 nt_errstr(status));
1847 goto err;
1851 * This crtime must be different from the root_crtime.
1852 * This checks we're actually correctly reading crtimes
1853 * from the filesystem.
1855 equal = (timespec_compare(&test_crtime, &root_crtime) == 0);
1856 if (equal) {
1857 printf("%s:%d Error. crtime of %s must differ from "
1858 "root_crtime\n",
1859 __FILE__,
1860 __LINE__,
1861 "BAD\\BAD\\file");
1862 goto err;
1866 * Test different SMB1 renames
1867 * and hard links.
1870 /* SMBmv only does rename. */
1871 ok = test_smb1_mv(cli,
1872 "BAD\\BAD\\file");
1873 if (!ok) {
1874 goto err;
1877 ok = test_smb1_setpathinfo_rename(cli,
1878 "BAD\\BAD\\file");
1879 if (!ok) {
1880 goto err;
1883 ok = test_smb1_setpathinfo_hardlink(cli,
1884 "BAD\\BAD\\file");
1885 if (!ok) {
1886 goto err;
1889 ok = test_smb1_setfileinfo_rename(cli,
1890 "BAD\\BAD\\file");
1891 if (!ok) {
1892 goto err;
1895 ok = test_smb1_setfileinfo_hardlink(cli,
1896 "BAD\\BAD\\file");
1897 if (!ok) {
1898 goto err;
1901 ok = test_smb1_ntrename_rename(cli,
1902 "BAD\\BAD\\file");
1903 if (!ok) {
1904 goto err;
1907 ok = test_smb1_ntrename_hardlink(cli,
1908 "BAD\\BAD\\file");
1909 if (!ok) {
1910 goto err;
1913 retval = true;
1915 err:
1917 if (fnum != (uint16_t)-1) {
1918 (void)smb1cli_close(cli->conn,
1919 cli->timeout,
1920 cli->smb1.pid,
1921 cli->smb1.tcon,
1922 cli->smb1.session,
1923 fnum,
1924 0); /* last_modified */
1927 /* Delete anything we made. */
1928 (void)smb1_dfs_delete(cli, "BAD\\BAD\\BAD");
1929 (void)smb1_dfs_delete(cli, "BAD\\BAD\\file");
1930 (void)smb1_dfs_delete(cli, "BAD\\BAD\\renamed_file");
1931 (void)smb1_dfs_delete(cli, "BAD\\BAD\\hlink");
1932 return retval;
1936 * SMB1 Findfirst. This is a minimal implementation
1937 * that expects all filename returns in one packet.
1938 * We're only using this to test the search DFS pathname
1939 * parsing.
1942 /****************************************************************************
1943 Calculate a safe next_entry_offset.
1944 ****************************************************************************/
1946 static size_t calc_next_entry_offset(const uint8_t *base,
1947 const uint8_t *pdata_end)
1949 size_t next_entry_offset = (size_t)PULL_LE_U32(base,0);
1951 if (next_entry_offset == 0 ||
1952 base + next_entry_offset < base ||
1953 base + next_entry_offset > pdata_end) {
1954 next_entry_offset = pdata_end - base;
1956 return next_entry_offset;
1959 static size_t get_filename(TALLOC_CTX *ctx,
1960 struct cli_state *cli,
1961 const uint8_t *base_ptr,
1962 uint16_t recv_flags2,
1963 const uint8_t *p,
1964 const uint8_t *pdata_end,
1965 struct file_info *finfo)
1967 size_t ret = 0;
1968 const uint8_t *base = p;
1969 size_t namelen = 0;
1970 size_t slen = 0;
1972 ZERO_STRUCTP(finfo);
1974 if (pdata_end - base < 94) {
1975 return pdata_end - base;
1977 p += 4; /* next entry offset */
1978 p += 4; /* fileindex */
1979 /* Offset zero is "create time", not "change time". */
1980 p += 8;
1981 finfo->atime_ts = interpret_long_date((const char *)p);
1982 p += 8;
1983 finfo->mtime_ts = interpret_long_date((const char *)p);
1984 p += 8;
1985 finfo->ctime_ts = interpret_long_date((const char *)p);
1986 p += 8;
1987 finfo->size = PULL_LE_U64(p, 0);
1988 p += 8;
1989 p += 8; /* alloc size */
1990 finfo->attr = PULL_LE_U32(p, 0);
1991 p += 4;
1992 namelen = PULL_LE_U32(p, 0);
1993 p += 4;
1994 p += 4; /* EA size */
1995 slen = PULL_LE_U8(p, 0);
1996 if (slen > 24) {
1997 /* Bad short name length. */
1998 return pdata_end - base;
2000 p += 2;
2001 ret = pull_string_talloc(ctx,
2002 base_ptr,
2003 recv_flags2,
2004 &finfo->short_name,
2006 slen,
2007 STR_UNICODE);
2008 if (ret == (size_t)-1) {
2009 return pdata_end - base;
2011 p += 24; /* short name */
2012 if (p + namelen < p || p + namelen > pdata_end) {
2013 return pdata_end - base;
2015 ret = pull_string_talloc(ctx,
2016 base_ptr,
2017 recv_flags2,
2018 &finfo->name,
2020 namelen,
2022 if (ret == (size_t)-1) {
2023 return pdata_end - base;
2025 return calc_next_entry_offset(base, pdata_end);
2028 /* Single shot SMB1 TRANS2 FindFirst. */
2030 static NTSTATUS smb1_findfirst(TALLOC_CTX *mem_ctx,
2031 struct cli_state *cli,
2032 const char *search_name,
2033 struct file_info **names,
2034 size_t *num_names)
2036 NTSTATUS status;
2037 uint16_t setup[1];
2038 uint8_t *param = NULL;
2039 uint16_t recv_flags2 = 0;
2040 uint8_t *rparam = NULL;
2041 uint32_t num_rparam = 0;
2042 uint8_t *rdata = NULL;
2043 uint32_t num_rdata = 0;
2044 uint16_t num_names_returned = 0;
2045 struct file_info *finfo = NULL;
2046 uint8_t *p2 = NULL;
2047 uint8_t *data_end = NULL;
2048 uint16_t i = 0;
2050 PUSH_LE_U16(&setup[0], 0, TRANSACT2_FINDFIRST);
2052 param = talloc_array(mem_ctx, uint8_t, 12);
2053 if (param == NULL) {
2054 return NT_STATUS_NO_MEMORY;
2057 PUSH_LE_U16(param, 0, FILE_ATTRIBUTE_DIRECTORY |
2058 FILE_ATTRIBUTE_SYSTEM |
2059 FILE_ATTRIBUTE_HIDDEN);
2060 PUSH_LE_U16(param, 2, 1366); /* max_matches */
2061 PUSH_LE_U16(param, 4, FLAG_TRANS2_FIND_CLOSE_IF_END);
2062 PUSH_LE_U16(param, 6, SMB_FIND_FILE_BOTH_DIRECTORY_INFO); /* info_level */
2064 param = trans2_bytes_push_str(param,
2065 smbXcli_conn_use_unicode(cli->conn),
2066 search_name,
2067 strlen(search_name)+1,
2068 NULL);
2069 if (param == NULL) {
2070 return NT_STATUS_NO_MEMORY;
2074 * A one shot SMB1 findfirst will be enough to
2075 * return ".", "..", and "file".
2077 status = cli_trans(mem_ctx,
2078 cli,
2079 SMBtrans2, /* cmd */
2080 NULL, /* pipe_name */
2081 0, /* fid */
2082 0, /* function */
2083 0, /* flags */
2084 &setup[0],
2085 1, /* num_setup uint16_t words */
2086 0, /* max returned setup */
2087 param,
2088 talloc_get_size(param), /* num_param */
2089 10, /* max returned param */
2090 NULL, /* data */
2091 0, /* num_data */
2092 SMB_BUFFER_SIZE_MAX, /* max retured data */
2093 /* Return values from here on.. */
2094 &recv_flags2, /* recv_flags2 */
2095 NULL, /* rsetup */
2096 0, /* min returned rsetup */
2097 NULL, /* num_rsetup */
2098 &rparam,
2099 6, /* min returned rparam */
2100 &num_rparam, /* number of returned rparam */
2101 &rdata,
2102 0, /* min returned rdata */
2103 &num_rdata);
2104 if (!NT_STATUS_IS_OK(status)) {
2105 return status;
2108 num_names_returned = PULL_LE_U16(rparam, 2);
2110 finfo = talloc_array(mem_ctx, struct file_info, num_names_returned);
2111 if (param == NULL) {
2112 return NT_STATUS_NO_MEMORY;
2115 p2 = rdata;
2116 data_end = rdata + num_rdata;
2118 for (i = 0; i < num_names_returned; i++) {
2119 if (p2 >= data_end) {
2120 break;
2122 if (i == num_names_returned - 1) {
2123 /* Last entry - fixup the last offset length. */
2124 PUSH_LE_U32(p2, 0, PTR_DIFF((rdata + num_rdata), p2));
2127 p2 += get_filename(mem_ctx,
2128 cli,
2129 rdata,
2130 recv_flags2,
2132 data_end,
2133 &finfo[i]);
2135 if (finfo->name == NULL) {
2136 printf("%s:%d Unable to parse name from listing "
2137 "of %s, position %u\n",
2138 __FILE__,
2139 __LINE__,
2140 search_name,
2141 (unsigned int)i);
2142 return NT_STATUS_INVALID_NETWORK_RESPONSE;
2145 *num_names = i;
2146 *names = finfo;
2147 return NT_STATUS_OK;
2151 * Test a specific SMB1 findfirst path to see if it
2152 * matches a given file array.
2154 static bool test_smb1_findfirst_path(struct cli_state *cli,
2155 const char *search_path,
2156 struct file_info *root_finfo,
2157 size_t num_root_finfo)
2159 size_t i = 0;
2160 size_t num_finfo = 0;
2161 struct file_info *finfo = NULL;
2162 NTSTATUS status;
2164 status = smb1_findfirst(talloc_tos(),
2165 cli,
2166 search_path,
2167 &finfo,
2168 &num_finfo);
2169 if (!NT_STATUS_IS_OK(status)) {
2170 printf("%s:%d smb1findfirst on %s returned %s\n",
2171 __FILE__,
2172 __LINE__,
2173 search_path,
2174 nt_errstr(status));
2175 return false;
2178 if (num_finfo != num_root_finfo) {
2179 printf("%s:%d On %s, num_finfo = %zu, num_root_finfo = %zu\n",
2180 __FILE__,
2181 __LINE__,
2182 search_path,
2183 num_finfo,
2184 num_root_finfo);
2185 return false;
2187 for (i = 0; i < num_finfo; i++) {
2188 bool match = strequal_m(finfo[i].name,
2189 root_finfo[i].name);
2190 if (!match) {
2191 printf("%s:%d Missmatch. For %s, at position %zu, "
2192 "finfo[i].name = %s, "
2193 "root_finfo[i].name = %s\n",
2194 __FILE__,
2195 __LINE__,
2196 search_path,
2198 finfo[i].name,
2199 root_finfo[i].name);
2200 return false;
2203 TALLOC_FREE(finfo);
2204 return true;
2208 * "Raw" test of doing a SMB1 findfirst to a DFS share.
2209 * We must (mostly) use the lower level smb1cli_XXXX() interfaces,
2210 * not the cli_XXX() ones here as the ultimate goal is to fix our
2211 * cli_XXX() interfaces to work transparently over DFS.
2213 * So here, we're testing the server code, not the client code.
2215 * Passes cleanly against Windows.
2218 bool run_smb1_dfs_search_paths(int dummy)
2220 struct cli_state *cli = NULL;
2221 NTSTATUS status;
2222 bool dfs_supported = false;
2223 struct file_info *root_finfo = NULL;
2224 size_t num_root_finfo = 0;
2225 bool retval = false;
2226 bool ok = false;
2227 uint16_t fnum = (uint16_t)-1;
2229 printf("Starting SMB1-DFS-SEARCH-PATHS\n");
2231 if (!torture_init_connection(&cli)) {
2232 return false;
2235 if (!torture_open_connection(&cli, 0)) {
2236 return false;
2239 /* Ensure this is a DFS share. */
2240 dfs_supported = smbXcli_conn_dfs_supported(cli->conn);
2241 if (!dfs_supported) {
2242 printf("Server %s does not support DFS\n",
2243 smbXcli_conn_remote_name(cli->conn));
2244 return false;
2246 dfs_supported = smbXcli_tcon_is_dfs_share(cli->smb1.tcon);
2247 if (!dfs_supported) {
2248 printf("Share %s does not support DFS\n",
2249 cli->share);
2250 return false;
2253 /* Start clean. */
2254 (void)smb1_dfs_delete(cli, "BAD\\BAD\\file");
2256 /* Create a test file to search for. */
2257 status = smb1cli_ntcreatex(cli->conn,
2258 cli->timeout,
2259 cli->smb1.pid,
2260 cli->smb1.tcon,
2261 cli->smb1.session,
2262 "BAD\\BAD\\file",
2263 OPLOCK_NONE, /* CreatFlags */
2264 0, /* RootDirectoryFid */
2265 SEC_STD_SYNCHRONIZE|
2266 SEC_STD_DELETE |
2267 SEC_FILE_READ_DATA|
2268 SEC_FILE_READ_ATTRIBUTE, /* DesiredAccess */
2269 0, /* AllocationSize */
2270 FILE_ATTRIBUTE_NORMAL, /* FileAttributes */
2271 FILE_SHARE_READ|
2272 FILE_SHARE_WRITE|
2273 FILE_SHARE_DELETE, /* ShareAccess */
2274 FILE_CREATE, /* CreateDisposition */
2275 0, /* CreateOptions */
2276 2, /* ImpersonationLevel */
2277 0, /* SecurityFlags */
2278 &fnum);
2279 if (!NT_STATUS_IS_OK(status)) {
2280 printf("%s:%d smb1cli_ntcreatex on %s returned %s\n",
2281 __FILE__,
2282 __LINE__,
2283 "BAD\\BAD\\file",
2284 nt_errstr(status));
2285 return false;
2288 /* Close "file" handle. */
2289 (void)smb1cli_close(cli->conn,
2290 cli->timeout,
2291 cli->smb1.pid,
2292 cli->smb1.tcon,
2293 cli->smb1.session,
2294 fnum,
2295 0); /* last_modified */
2296 fnum = (uint16_t)-1;
2298 /* Get the list of files in the share. */
2299 status = smb1_findfirst(talloc_tos(),
2300 cli,
2301 "SERVER\\SHARE\\*",
2302 &root_finfo,
2303 &num_root_finfo);
2304 if (!NT_STATUS_IS_OK(status)) {
2305 printf("%s:%d smb1findfirst on %s returned %s\n",
2306 __FILE__,
2307 __LINE__,
2308 "SERVER\\SHARE\\*",
2309 nt_errstr(status));
2310 return false;
2314 * Try different search names. They should
2315 * all match the root directory list.
2317 ok = test_smb1_findfirst_path(cli,
2318 "\\SERVER\\SHARE\\*",
2319 root_finfo,
2320 num_root_finfo);
2321 if (!ok) {
2322 goto err;
2325 ok = test_smb1_findfirst_path(cli,
2326 "*",
2327 root_finfo,
2328 num_root_finfo);
2329 if (!ok) {
2330 goto err;
2332 ok = test_smb1_findfirst_path(cli,
2333 "\\*",
2334 root_finfo,
2335 num_root_finfo);
2336 if (!ok) {
2337 goto err;
2339 ok = test_smb1_findfirst_path(cli,
2340 "\\SERVER\\*",
2341 root_finfo,
2342 num_root_finfo);
2343 if (!ok) {
2344 goto err;
2346 retval = true;
2348 err:
2350 if (fnum != (uint16_t)-1) {
2351 (void)smb1cli_close(cli->conn,
2352 cli->timeout,
2353 cli->smb1.pid,
2354 cli->smb1.tcon,
2355 cli->smb1.session,
2356 fnum,
2357 0); /* last_modified */
2360 /* Delete anything we made. */
2361 (void)smb1_dfs_delete(cli, "BAD\\BAD\\file");
2362 return retval;
2365 static bool smb1_create_testfile(struct cli_state *cli,
2366 const char *path)
2368 NTSTATUS status;
2369 uint16_t fnum = (uint16_t)-1;
2371 /* Create a test file. */
2372 status = smb1cli_ntcreatex(cli->conn,
2373 cli->timeout,
2374 cli->smb1.pid,
2375 cli->smb1.tcon,
2376 cli->smb1.session,
2377 path,
2378 OPLOCK_NONE, /* CreatFlags */
2379 0, /* RootDirectoryFid */
2380 SEC_STD_SYNCHRONIZE|
2381 SEC_STD_DELETE |
2382 SEC_FILE_READ_DATA|
2383 SEC_FILE_READ_ATTRIBUTE, /* DesiredAccess */
2384 0, /* AllocationSize */
2385 FILE_ATTRIBUTE_NORMAL, /* FileAttributes */
2386 FILE_SHARE_READ|
2387 FILE_SHARE_WRITE|
2388 FILE_SHARE_DELETE, /* ShareAccess */
2389 FILE_CREATE, /* CreateDisposition */
2390 0, /* CreateOptions */
2391 2, /* ImpersonationLevel */
2392 0, /* SecurityFlags */
2393 &fnum);
2394 if (!NT_STATUS_IS_OK(status)) {
2395 printf("%s:%d smb1cli_ntcreatex on %s returned %s\n",
2396 __FILE__,
2397 __LINE__,
2398 path,
2399 nt_errstr(status));
2400 return false;
2403 /* Close "file" handle. */
2404 (void)smb1cli_close(cli->conn,
2405 cli->timeout,
2406 cli->smb1.pid,
2407 cli->smb1.tcon,
2408 cli->smb1.session,
2409 fnum,
2410 0); /* last_modified */
2411 return true;
2414 static NTSTATUS smb1_unlink(struct cli_state *cli,
2415 const char *path)
2417 uint16_t vwv[1];
2418 uint8_t *bytes = NULL;
2420 PUSH_LE_U16(vwv, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2421 bytes = talloc_array(talloc_tos(), uint8_t, 1);
2422 if (bytes == NULL) {
2423 return NT_STATUS_NO_MEMORY;
2425 bytes[0] = 4;
2426 bytes = smb_bytes_push_str(bytes,
2427 smbXcli_conn_use_unicode(cli->conn),
2428 path,
2429 strlen(path)+1,
2430 NULL);
2431 if (bytes == NULL) {
2432 return NT_STATUS_NO_MEMORY;
2435 return cli_smb(talloc_tos(),
2436 cli,
2437 SMBunlink, /* command. */
2438 0, /* additional_flags. */
2439 1, /* wct. */
2440 vwv, /* vwv. */
2441 talloc_get_size(bytes), /* num_bytes. */
2442 bytes, /* bytes. */
2443 NULL, /* result parent. */
2444 0, /* min_wct. */
2445 NULL, /* return wcount. */
2446 NULL, /* return wvw. */
2447 NULL, /* return byte count. */
2448 NULL); /* return bytes. */
2451 static bool test_smb1_unlink(struct cli_state *cli)
2453 NTSTATUS status;
2454 bool retval = false;
2455 bool ok = false;
2457 /* Start clean. */
2458 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\file");
2460 /* Create a test file. */
2461 ok = smb1_create_testfile(cli, "\\BAD\\BAD\\file");
2462 if (!ok) {
2463 printf("%s:%d failed to create test file %s\n",
2464 __FILE__,
2465 __LINE__,
2466 "\\BAD\\BAD\\file");
2467 goto err;
2470 status = smb1_unlink(cli, "file");
2471 if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
2472 printf("%s:%d SMB1unlink of %s should get "
2473 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
2474 __FILE__,
2475 __LINE__,
2476 "file",
2477 nt_errstr(status));
2478 goto err;
2480 status = smb1_unlink(cli, "\\BAD\\file");
2481 if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
2482 printf("%s:%d SMB1unlink of %s should get "
2483 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
2484 __FILE__,
2485 __LINE__,
2486 "\\BAD\\file",
2487 nt_errstr(status));
2488 goto err;
2490 status = smb1_unlink(cli, "\\BAD\\BAD\\file");
2491 if (!NT_STATUS_IS_OK(status)) {
2492 printf("%s:%d SMB1unlink on %s returned %s\n",
2493 __FILE__,
2494 __LINE__,
2495 "\\BAD\\BAD\\file",
2496 nt_errstr(status));
2497 goto err;
2500 retval = true;
2502 err:
2504 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\file");
2505 return retval;
2508 static NTSTATUS smb1_mkdir(struct cli_state *cli,
2509 const char *path)
2511 uint8_t *bytes = NULL;
2513 bytes = talloc_array(talloc_tos(), uint8_t, 1);
2514 if (bytes == NULL) {
2515 return NT_STATUS_NO_MEMORY;
2517 bytes[0] = 4;
2518 bytes = smb_bytes_push_str(bytes,
2519 smbXcli_conn_use_unicode(cli->conn),
2520 path,
2521 strlen(path)+1,
2522 NULL);
2523 if (bytes == NULL) {
2524 return NT_STATUS_NO_MEMORY;
2527 return cli_smb(talloc_tos(),
2528 cli,
2529 SMBmkdir, /* command. */
2530 0, /* additional_flags. */
2531 0, /* wct. */
2532 NULL, /* vwv. */
2533 talloc_get_size(bytes), /* num_bytes. */
2534 bytes, /* bytes. */
2535 NULL, /* result parent. */
2536 0, /* min_wct. */
2537 NULL, /* return wcount. */
2538 NULL, /* return wvw. */
2539 NULL, /* return byte count. */
2540 NULL); /* return bytes. */
2543 static bool test_smb1_mkdir(struct cli_state *cli)
2545 NTSTATUS status;
2546 bool retval = false;
2548 /* Start clean. */
2549 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\dir");
2551 status = smb1_mkdir(cli, "dir");
2552 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2553 printf("%s:%d SMB1mkdir of %s should get "
2554 "NT_STATUS_OBJECT_NAME_COLLISION, got %s\n",
2555 __FILE__,
2556 __LINE__,
2557 "dir",
2558 nt_errstr(status));
2559 goto err;
2561 status = smb1_mkdir(cli, "\\BAD\\dir");
2562 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2563 printf("%s:%d SMB1mkdir of %s should get "
2564 "NT_STATUS_OBJECT_NAME_COLLISION, got %s\n",
2565 __FILE__,
2566 __LINE__,
2567 "\\BAD\\dir",
2568 nt_errstr(status));
2569 goto err;
2571 status = smb1_mkdir(cli, "\\BAD\\BAD\\dir");
2572 if (!NT_STATUS_IS_OK(status)) {
2573 printf("%s:%d SMB1mkdir on %s returned %s\n",
2574 __FILE__,
2575 __LINE__,
2576 "\\BAD\\BAD\\dir",
2577 nt_errstr(status));
2578 goto err;
2581 retval = true;
2583 err:
2585 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\dir");
2586 return retval;
2589 static NTSTATUS smb1_rmdir(struct cli_state *cli,
2590 const char *path)
2592 uint8_t *bytes = NULL;
2594 bytes = talloc_array(talloc_tos(), uint8_t, 1);
2595 if (bytes == NULL) {
2596 return NT_STATUS_NO_MEMORY;
2598 bytes[0] = 4;
2599 bytes = smb_bytes_push_str(bytes,
2600 smbXcli_conn_use_unicode(cli->conn),
2601 path,
2602 strlen(path)+1,
2603 NULL);
2604 if (bytes == NULL) {
2605 return NT_STATUS_NO_MEMORY;
2608 return cli_smb(talloc_tos(),
2609 cli,
2610 SMBrmdir, /* command. */
2611 0, /* additional_flags. */
2612 0, /* wct. */
2613 NULL, /* vwv. */
2614 talloc_get_size(bytes), /* num_bytes. */
2615 bytes, /* bytes. */
2616 NULL, /* result parent. */
2617 0, /* min_wct. */
2618 NULL, /* return wcount. */
2619 NULL, /* return wvw. */
2620 NULL, /* return byte count. */
2621 NULL); /* return bytes. */
2624 static bool test_smb1_rmdir(struct cli_state *cli)
2626 NTSTATUS status;
2627 bool retval = false;
2629 /* Start clean. */
2630 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\dir");
2632 status = smb1_mkdir(cli, "\\BAD\\BAD\\dir");
2633 if (!NT_STATUS_IS_OK(status)) {
2634 printf("%s:%d SMB1rmdir on %s returned %s\n",
2635 __FILE__,
2636 __LINE__,
2637 "\\BAD\\BAD\\dir",
2638 nt_errstr(status));
2639 goto err;
2642 status = smb1_rmdir(cli, "dir");
2643 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
2644 printf("%s:%d SMB1rmdir of %s should get "
2645 "NT_STATUS_ACCESS_DENIED, got %s\n",
2646 __FILE__,
2647 __LINE__,
2648 "dir",
2649 nt_errstr(status));
2650 goto err;
2652 status = smb1_rmdir(cli, "\\BAD\\dir");
2653 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
2654 printf("%s:%d SMB1rmdir of %s should get "
2655 "NT_STATUS_ACCESS_DENIED, got %s\n",
2656 __FILE__,
2657 __LINE__,
2658 "\\BAD\\dir",
2659 nt_errstr(status));
2660 goto err;
2662 status = smb1_rmdir(cli, "\\BAD\\BAD\\dir");
2663 if (!NT_STATUS_IS_OK(status)) {
2664 printf("%s:%d SMB1rmdir on %s returned %s\n",
2665 __FILE__,
2666 __LINE__,
2667 "\\BAD\\BAD\\dir",
2668 nt_errstr(status));
2669 goto err;
2672 retval = true;
2674 err:
2676 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\dir");
2677 return retval;
2680 static NTSTATUS smb1_ntcreatex(struct cli_state *cli,
2681 const char *path)
2683 NTSTATUS status;
2684 uint16_t fnum = (uint16_t)-1;
2686 status = smb1cli_ntcreatex(cli->conn,
2687 cli->timeout,
2688 cli->smb1.pid,
2689 cli->smb1.tcon,
2690 cli->smb1.session,
2691 path,
2692 OPLOCK_NONE, /* CreatFlags */
2693 0, /* RootDirectoryFid */
2694 SEC_STD_SYNCHRONIZE|
2695 SEC_STD_DELETE |
2696 SEC_FILE_READ_DATA|
2697 SEC_FILE_READ_ATTRIBUTE, /* DesiredAccess */
2698 0, /* AllocationSize */
2699 FILE_ATTRIBUTE_NORMAL, /* FileAttributes */
2700 FILE_SHARE_READ|
2701 FILE_SHARE_WRITE|
2702 FILE_SHARE_DELETE, /* ShareAccess */
2703 FILE_CREATE, /* CreateDisposition */
2704 0, /* CreateOptions */
2705 2, /* ImpersonationLevel */
2706 0, /* SecurityFlags */
2707 &fnum);
2708 if (!NT_STATUS_IS_OK(status)) {
2709 return status;
2712 /* Close "file" handle. */
2713 (void)smb1cli_close(cli->conn,
2714 cli->timeout,
2715 cli->smb1.pid,
2716 cli->smb1.tcon,
2717 cli->smb1.session,
2718 fnum,
2719 0); /* last_modified */
2720 return NT_STATUS_OK;
2723 static bool test_smb1_ntcreatex(struct cli_state *cli)
2725 NTSTATUS status;
2726 bool retval = false;
2728 /* Start clean. */
2729 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\ntcreateXfile");
2731 status = smb1_ntcreatex(cli, "ntcreateXfile");
2732 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2733 printf("%s:%d SMB1ntcreateX of %s should get "
2734 "NT_STATUS_OBJECT_NAME_COLLISION, got %s\n",
2735 __FILE__,
2736 __LINE__,
2737 "ntcreateXfile",
2738 nt_errstr(status));
2739 goto err;
2741 status = smb1_ntcreatex(cli, "\\BAD\\ntcreateXfile");
2742 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2743 printf("%s:%d SMB1ntcreateX of %s should get "
2744 "NT_STATUS_OBJECT_NAME_COLLISION, got %s\n",
2745 __FILE__,
2746 __LINE__,
2747 "\\BAD\\ntcreateXfile",
2748 nt_errstr(status));
2749 goto err;
2751 status = smb1_ntcreatex(cli, "\\BAD\\BAD\\ntcreateXfile");
2752 if (!NT_STATUS_IS_OK(status)) {
2753 printf("%s:%d SMB1ntcreateX on %s returned %s\n",
2754 __FILE__,
2755 __LINE__,
2756 "\\BAD\\BAD\\ntcreateXfile",
2757 nt_errstr(status));
2758 goto err;
2761 retval = true;
2763 err:
2765 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\ntcreateXfile");
2766 return retval;
2769 static NTSTATUS smb1_nttrans_create(struct cli_state *cli,
2770 const char *path)
2772 uint8_t *param = NULL;
2773 size_t converted_len = 0;
2774 uint8_t *rparam = NULL;
2775 uint32_t num_rparam = 0;
2776 uint16_t fnum = (uint16_t)-1;
2777 NTSTATUS status;
2779 param = talloc_zero_array(talloc_tos(), uint8_t, 53);
2780 if (param == NULL) {
2781 return NT_STATUS_NO_MEMORY;
2784 param = trans2_bytes_push_str(param,
2785 smbXcli_conn_use_unicode(cli->conn),
2786 path,
2787 strlen(path),
2788 &converted_len);
2789 if (param == NULL) {
2790 return NT_STATUS_NO_MEMORY;
2793 PUSH_LE_U32(param, 8, SEC_STD_SYNCHRONIZE|
2794 SEC_STD_DELETE |
2795 SEC_FILE_READ_DATA|
2796 SEC_FILE_READ_ATTRIBUTE); /* DesiredAccess */
2797 PUSH_LE_U32(param, 20, FILE_ATTRIBUTE_NORMAL);
2798 PUSH_LE_U32(param, 24, FILE_SHARE_READ|
2799 FILE_SHARE_WRITE|
2800 FILE_SHARE_DELETE); /* ShareAccess */
2801 PUSH_LE_U32(param, 28, FILE_CREATE);
2802 PUSH_LE_U32(param, 44, converted_len);
2803 PUSH_LE_U32(param, 48, 0x02); /* ImpersonationLevel */
2805 status = cli_trans(talloc_tos(),
2806 cli,
2807 SMBnttrans, /* trans cmd */
2808 NULL, /* pipe_name */
2809 0, /* fid */
2810 NT_TRANSACT_CREATE, /* function */
2811 0, /* flags */
2812 NULL, /* setup */
2813 0, /* num_setup */
2814 0, /* max_setup */
2815 param, /* param */
2816 talloc_get_size(param), /* num_param */
2817 128, /* max_param */
2818 NULL, /* data */
2819 0, /* num_data */
2820 0, /* max_data */
2821 NULL, /* recv_flags2 */
2822 NULL, /* rsetup */
2823 0, /* min_rsetup */
2824 NULL, /* num_rsetup */
2825 &rparam, /* rparam */
2826 69, /* min_rparam */
2827 &num_rparam, /* num_rparam */
2828 NULL, /* rdata */
2829 0, /* min_rdata */
2830 NULL); /* num_rdata */
2831 if (!NT_STATUS_IS_OK(status)) {
2832 return status;
2834 fnum = PULL_LE_U16(param, 2);
2835 /* Close "file" handle. */
2836 (void)smb1cli_close(cli->conn,
2837 cli->timeout,
2838 cli->smb1.pid,
2839 cli->smb1.tcon,
2840 cli->smb1.session,
2841 fnum,
2842 0); /* last_modified */
2843 return NT_STATUS_OK;
2846 static bool test_smb1_nttrans_create(struct cli_state *cli)
2848 NTSTATUS status;
2849 bool retval = false;
2851 /* Start clean. */
2852 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\nttransfile");
2854 status = smb1_nttrans_create(cli, "nttransfile");
2855 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2856 printf("%s:%d SMB1trans NT_TRANSACT_CREATE of %s should get "
2857 "NT_STATUS_OBJECT_NAME_COLLISION, got %s\n",
2858 __FILE__,
2859 __LINE__,
2860 "nttransfile",
2861 nt_errstr(status));
2862 goto err;
2864 status = smb1_nttrans_create(cli, "\\BAD\\nttransfile");
2865 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2866 printf("%s:%d SMB1trans NT_TRANSACT_CREATE of %s should get "
2867 "NT_STATUS_OBJECT_NAME_COLLISION, got %s\n",
2868 __FILE__,
2869 __LINE__,
2870 "\\BAD\\nttransfile",
2871 nt_errstr(status));
2872 goto err;
2874 status = smb1_nttrans_create(cli, "\\BAD\\BAD\\nttransfile");
2875 if (!NT_STATUS_IS_OK(status)) {
2876 printf("%s:%d SMB1trans NT_TRANSACT_CREATE on %s returned %s\n",
2877 __FILE__,
2878 __LINE__,
2879 "\\BAD\\BAD\\nttransfile",
2880 nt_errstr(status));
2881 goto err;
2884 retval = true;
2886 err:
2888 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\nttransfile");
2889 return retval;
2892 struct smb1_openx_state {
2893 const char *fname;
2894 uint16_t vwv[15];
2895 uint16_t fnum;
2896 struct iovec bytes;
2899 static void smb1_openx_done(struct tevent_req *subreq);
2901 static struct tevent_req *smb1_openx_send(TALLOC_CTX *mem_ctx,
2902 struct tevent_context *ev,
2903 struct cli_state *cli,
2904 const char *path)
2906 struct tevent_req *req = NULL;
2907 struct tevent_req *subreq = NULL;
2908 uint16_t accessmode = 0;
2909 struct smb1_openx_state *state = NULL;
2910 uint8_t *bytes = NULL;
2911 NTSTATUS status;
2913 req = tevent_req_create(mem_ctx, &state, struct smb1_openx_state);
2914 if (req == NULL) {
2915 return NULL;
2918 accessmode = (DENY_NONE<<4);
2919 accessmode |= DOS_OPEN_RDONLY;
2921 PUSH_LE_U8(state->vwv + 0, 0, 0xFF);
2922 PUSH_LE_U16(state->vwv + 3, 0, accessmode);
2923 PUSH_LE_U16(state->vwv + 4, 0,
2924 FILE_ATTRIBUTE_SYSTEM |
2925 FILE_ATTRIBUTE_HIDDEN |
2926 FILE_ATTRIBUTE_DIRECTORY);
2927 PUSH_LE_U16(state->vwv + 8,
2929 OPENX_FILE_CREATE_IF_NOT_EXIST| OPENX_FILE_EXISTS_FAIL);
2931 bytes = talloc_array(state, uint8_t, 0);
2932 if (tevent_req_nomem(bytes, req)) {
2933 return tevent_req_post(req, ev);
2935 bytes = smb_bytes_push_str(bytes,
2936 smbXcli_conn_use_unicode(cli->conn),
2937 path,
2938 strlen(path)+1,
2939 NULL);
2940 if (tevent_req_nomem(bytes, req)) {
2941 return tevent_req_post(req, ev);
2944 state->bytes.iov_base = (void *)bytes;
2945 state->bytes.iov_len = talloc_get_size(bytes);
2946 subreq = cli_smb_req_create(state,
2948 cli,
2949 SMBopenX, /* cmd */
2950 0, /* additional_flags */
2951 0, /* additional_flags2 */
2952 15, /* num_vwv */
2953 state->vwv, /* vwv */
2954 1, /* iovcount */
2955 &state->bytes); /* iovec */
2956 if (tevent_req_nomem(subreq, req)) {
2957 return tevent_req_post(req, ev);
2959 tevent_req_set_callback(subreq, smb1_openx_done, req);
2961 status = smb1cli_req_chain_submit(&subreq, 1);
2962 if (tevent_req_nterror(req, status)) {
2963 return tevent_req_post(req, ev);
2965 return req;
2968 static void smb1_openx_done(struct tevent_req *subreq)
2970 struct tevent_req *req = tevent_req_callback_data(
2971 subreq, struct tevent_req);
2972 struct smb1_openx_state *state = tevent_req_data(
2973 req, struct smb1_openx_state);
2974 uint8_t wct = 0;
2975 uint16_t *vwv = NULL;
2976 NTSTATUS status;
2978 status = cli_smb_recv(subreq,
2979 state,
2980 NULL, /* pinbuf */
2981 3, /* min_wct */
2982 &wct, /* wct */
2983 &vwv, /* vwv */
2984 NULL, /* num_rbytes */
2985 NULL); /* rbytes */
2986 TALLOC_FREE(subreq);
2987 if (tevent_req_nterror(req, status)) {
2988 return;
2990 state->fnum = PULL_LE_U16(vwv+2, 0);
2991 tevent_req_done(req);
2994 static NTSTATUS smb1_openx_recv(struct tevent_req *req, uint16_t *pfnum)
2996 struct smb1_openx_state *state = tevent_req_data(
2997 req, struct smb1_openx_state);
2998 NTSTATUS status;
3000 if (tevent_req_is_nterror(req, &status)) {
3001 return status;
3003 *pfnum = state->fnum;
3004 return NT_STATUS_OK;
3007 static NTSTATUS smb1_openx(struct cli_state *cli, const char *path)
3009 TALLOC_CTX *frame = talloc_stackframe();
3010 struct tevent_context *ev = NULL;
3011 struct tevent_req *req = NULL;
3012 uint16_t fnum = (uint16_t)-1;
3013 NTSTATUS status = NT_STATUS_NO_MEMORY;
3015 ev = samba_tevent_context_init(frame);
3016 if (ev == NULL) {
3017 goto fail;
3020 req = smb1_openx_send(frame,
3022 cli,
3023 path);
3024 if (req == NULL) {
3025 goto fail;
3028 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3029 goto fail;
3032 status = smb1_openx_recv(req, &fnum);
3033 fail:
3035 /* Close "file" handle. */
3036 if (fnum != (uint16_t)-1) {
3037 (void)smb1cli_close(cli->conn,
3038 cli->timeout,
3039 cli->smb1.pid,
3040 cli->smb1.tcon,
3041 cli->smb1.session,
3042 fnum,
3043 0); /* last_modified */
3045 TALLOC_FREE(frame);
3046 return status;
3049 static bool test_smb1_openx(struct cli_state *cli)
3051 NTSTATUS status;
3052 bool retval = false;
3054 /* Start clean. */
3055 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\openxfile");
3057 status = smb1_openx(cli, "openxfile");
3058 if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
3059 printf("%s:%d SMB1openx of %s should get "
3060 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3061 __FILE__,
3062 __LINE__,
3063 "openxfile",
3064 nt_errstr(status));
3065 goto err;
3067 status = smb1_openx(cli, "\\BAD\\openxfile");
3068 if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
3069 printf("%s:%d SMB1openx of %s should get "
3070 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3071 __FILE__,
3072 __LINE__,
3073 "\\BAD\\openxfile",
3074 nt_errstr(status));
3075 goto err;
3077 status = smb1_openx(cli, "\\BAD\\BAD\\openxfile");
3078 if (!NT_STATUS_IS_OK(status)) {
3079 printf("%s:%d SMB1openx on %s returned %s\n",
3080 __FILE__,
3081 __LINE__,
3082 "\\BAD\\BAD\\openxfile",
3083 nt_errstr(status));
3084 goto err;
3087 retval = true;
3089 err:
3091 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\openxfile");
3092 return retval;
3095 static NTSTATUS smb1_open(struct cli_state *cli,
3096 const char *path,
3097 uint16_t *pfnum)
3099 uint16_t vwv[2] = { 0, 0};
3100 uint8_t *bytes = NULL;
3101 uint16_t accessmode = 0;
3102 uint16_t *return_words = NULL;
3103 uint8_t return_wcount = 0;
3104 NTSTATUS status;
3106 accessmode = (DENY_NONE<<4);
3107 accessmode |= DOS_OPEN_RDONLY;
3109 PUSH_LE_U16(vwv + 0, 0, accessmode);
3110 PUSH_LE_U16(vwv + 1, 0, FILE_ATTRIBUTE_NORMAL);
3112 bytes = talloc_array(talloc_tos(), uint8_t, 1);
3113 if (bytes == NULL) {
3114 return NT_STATUS_NO_MEMORY;
3116 bytes[0] = 4;
3117 bytes = smb_bytes_push_str(bytes,
3118 smbXcli_conn_use_unicode(cli->conn),
3119 path,
3120 strlen(path)+1,
3121 NULL);
3122 if (bytes == NULL) {
3123 return NT_STATUS_NO_MEMORY;
3126 status = cli_smb(talloc_tos(),
3127 cli,
3128 SMBopen, /* command. */
3129 0, /* additional_flags. */
3130 2, /* wct. */
3131 vwv, /* vwv. */
3132 talloc_get_size(bytes), /* num_bytes. */
3133 bytes, /* bytes. */
3134 NULL, /* result parent. */
3135 7, /* min_wct. */
3136 &return_wcount, /* return wcount. */
3137 &return_words, /* return wvw. */
3138 NULL, /* return byte count. */
3139 NULL); /* return bytes. */
3140 if (!NT_STATUS_IS_OK(status)) {
3141 return status;
3143 *pfnum = PULL_LE_U16(return_words, 0);
3144 return status;
3147 static bool test_smb1_open(struct cli_state *cli)
3149 NTSTATUS status;
3150 bool retval = false;
3151 bool ok = false;
3152 bool equal = false;
3153 uint16_t fnum = (uint16_t)-1;
3154 struct timespec testfile_crtime = { 0 };
3155 struct timespec open_crtime = { 0 };
3157 /* Start clean. */
3158 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\openfile");
3160 /* Create a test file. */
3161 ok = smb1_create_testfile(cli, "\\BAD\\BAD\\openfile");
3162 if (!ok) {
3163 printf("%s:%d failed to create test file %s\n",
3164 __FILE__,
3165 __LINE__,
3166 "\\BAD\\BAD\\openfile");
3167 goto err;
3170 /* Get the test file crtime number. */
3171 status = get_smb1_crtime(cli,
3172 "\\BAD\\BAD\\openfile",
3173 &testfile_crtime);
3174 if (!NT_STATUS_IS_OK(status)) {
3175 printf("%s:%d Failed to get crtime for %s, (%s)\n",
3176 __FILE__,
3177 __LINE__,
3178 "\\BAD\\BAD\\openfile",
3179 nt_errstr(status));
3180 goto err;
3183 status = smb1_open(cli, "openfile", &fnum);
3184 if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
3185 printf("%s:%d SMB1open of %s should get "
3186 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3187 __FILE__,
3188 __LINE__,
3189 "openfile",
3190 nt_errstr(status));
3191 goto err;
3193 status = smb1_open(cli, "\\BAD\\openfile", &fnum);
3194 if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
3195 printf("%s:%d SMB1open of %s should get "
3196 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3197 __FILE__,
3198 __LINE__,
3199 "\\BAD\\openfile",
3200 nt_errstr(status));
3201 goto err;
3203 status = smb1_open(cli, "\\BAD\\BAD\\openfile", &fnum);
3204 if (!NT_STATUS_IS_OK(status)) {
3205 printf("%s:%d failed to open test file %s (%s)\n",
3206 __FILE__,
3207 __LINE__,
3208 "\\BAD\\BAD\\openfile",
3209 nt_errstr(status));
3210 goto err;
3213 status = cli_qfileinfo_basic(cli,
3214 fnum,
3215 NULL, /* attr */
3216 NULL, /* size */
3217 &open_crtime, /* create_time */
3218 NULL, /* access_time */
3219 NULL, /* write_time */
3220 NULL, /* change_time */
3221 NULL); /* ino */
3222 if (!NT_STATUS_IS_OK(status)) {
3223 printf("%s:%d failed to get crtime of test file %s (%s)\n",
3224 __FILE__,
3225 __LINE__,
3226 "\\BAD\\BAD\\openfile",
3227 nt_errstr(status));
3228 goto err;
3230 equal = (timespec_compare(&testfile_crtime, &open_crtime) == 0);
3231 if (!equal) {
3232 printf("%s:%d crtime missmatch of test file %s\n",
3233 __FILE__,
3234 __LINE__,
3235 "\\BAD\\BAD\\openfile");
3236 goto err;
3239 retval = true;
3241 err:
3243 /* Close "openfile" handle. */
3244 if (fnum != (uint16_t)-1) {
3245 (void)smb1cli_close(cli->conn,
3246 cli->timeout,
3247 cli->smb1.pid,
3248 cli->smb1.tcon,
3249 cli->smb1.session,
3250 fnum,
3251 0); /* last_modified */
3253 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\openfile");
3254 return retval;
3257 static NTSTATUS smb1_create(struct cli_state *cli,
3258 const char *path,
3259 uint16_t smb1_operation,
3260 uint16_t *pfnum)
3262 uint16_t vwv[3] = { 0, 0, 0};
3263 uint8_t *bytes = NULL;
3264 uint16_t accessmode = 0;
3265 uint16_t *return_words = NULL;
3266 uint8_t return_wcount = 0;
3267 NTSTATUS status;
3269 accessmode = (DENY_NONE<<4);
3270 accessmode |= DOS_OPEN_RDONLY;
3272 PUSH_LE_U16(vwv + 0, 0, FILE_ATTRIBUTE_NORMAL);
3274 bytes = talloc_array(talloc_tos(), uint8_t, 1);
3275 if (bytes == NULL) {
3276 return NT_STATUS_NO_MEMORY;
3278 bytes[0] = 4;
3279 bytes = smb_bytes_push_str(bytes,
3280 smbXcli_conn_use_unicode(cli->conn),
3281 path,
3282 strlen(path)+1,
3283 NULL);
3284 if (bytes == NULL) {
3285 return NT_STATUS_NO_MEMORY;
3288 status = cli_smb(talloc_tos(),
3289 cli,
3290 smb1_operation, /* command. */
3291 0, /* additional_flags. */
3292 3, /* wct. */
3293 vwv, /* vwv. */
3294 talloc_get_size(bytes), /* num_bytes. */
3295 bytes, /* bytes. */
3296 NULL, /* result parent. */
3297 1, /* min_wct. */
3298 &return_wcount, /* return wcount. */
3299 &return_words, /* return wvw. */
3300 NULL, /* return byte count. */
3301 NULL); /* return bytes. */
3302 if (!NT_STATUS_IS_OK(status)) {
3303 return status;
3305 *pfnum = PULL_LE_U16(return_words, 0);
3306 return status;
3309 static bool test_smb1_create(struct cli_state *cli)
3311 NTSTATUS status;
3312 bool retval = false;
3313 uint16_t fnum = (uint16_t)-1;
3315 /* Start clean. */
3316 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\createfile");
3317 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\mknewfile");
3319 status = smb1_create(cli, "createfile", SMBcreate, &fnum);
3320 if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
3321 printf("%s:%d SMB1create of %s should get "
3322 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3323 __FILE__,
3324 __LINE__,
3325 "createfile",
3326 nt_errstr(status));
3327 goto err;
3329 status = smb1_create(cli, "\\BAD\\createfile", SMBcreate, &fnum);
3330 if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
3331 printf("%s:%d SMB1open of %s should get "
3332 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3333 __FILE__,
3334 __LINE__,
3335 "\\BAD\\openfile",
3336 nt_errstr(status));
3337 goto err;
3339 status = smb1_create(cli, "\\BAD\\BAD\\createfile", SMBcreate, &fnum);
3340 if (!NT_STATUS_IS_OK(status)) {
3341 printf("%s:%d failed to create file %s (%s)\n",
3342 __FILE__,
3343 __LINE__,
3344 "\\BAD\\BAD\\createfile",
3345 nt_errstr(status));
3346 goto err;
3349 (void)smb1cli_close(cli->conn,
3350 cli->timeout,
3351 cli->smb1.pid,
3352 cli->smb1.tcon,
3353 cli->smb1.session,
3354 fnum,
3355 0); /* last_modified */
3357 fnum = (uint16_t)-1;
3359 /* Now do the same with SMBmknew */
3360 status = smb1_create(cli, "mknewfile", SMBmknew, &fnum);
3361 if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
3362 printf("%s:%d SMB1mknew of %s should get "
3363 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3364 __FILE__,
3365 __LINE__,
3366 "mknewfile",
3367 nt_errstr(status));
3368 goto err;
3370 status = smb1_create(cli, "\\BAD\\mknewfile", SMBmknew, &fnum);
3371 if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
3372 printf("%s:%d SMB1mknew of %s should get "
3373 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3374 __FILE__,
3375 __LINE__,
3376 "\\BAD\\mknewfile",
3377 nt_errstr(status));
3378 goto err;
3380 status = smb1_create(cli, "\\BAD\\BAD\\mknewfile", SMBmknew, &fnum);
3381 if (!NT_STATUS_IS_OK(status)) {
3382 printf("%s:%d failed to create file %s (%s)\n",
3383 __FILE__,
3384 __LINE__,
3385 "\\BAD\\BAD\\mknewfile",
3386 nt_errstr(status));
3387 goto err;
3390 (void)smb1cli_close(cli->conn,
3391 cli->timeout,
3392 cli->smb1.pid,
3393 cli->smb1.tcon,
3394 cli->smb1.session,
3395 fnum,
3396 0); /* last_modified */
3398 fnum = (uint16_t)-1;
3400 retval = true;
3402 err:
3404 /* Close "openfile" handle. */
3405 if (fnum != (uint16_t)-1) {
3406 (void)smb1cli_close(cli->conn,
3407 cli->timeout,
3408 cli->smb1.pid,
3409 cli->smb1.tcon,
3410 cli->smb1.session,
3411 fnum,
3412 0); /* last_modified */
3414 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\createfile");
3415 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\mknewfile");
3416 return retval;
3419 static NTSTATUS smb1_getatr(struct cli_state *cli,
3420 const char *path,
3421 uint16_t *pattr)
3423 uint8_t *bytes = NULL;
3424 uint16_t *return_words = NULL;
3425 uint8_t return_wcount = 0;
3426 NTSTATUS status;
3428 bytes = talloc_array(talloc_tos(), uint8_t, 1);
3429 if (bytes == NULL) {
3430 return NT_STATUS_NO_MEMORY;
3432 bytes[0] = 4;
3433 bytes = smb_bytes_push_str(bytes,
3434 smbXcli_conn_use_unicode(cli->conn),
3435 path,
3436 strlen(path)+1,
3437 NULL);
3438 if (bytes == NULL) {
3439 return NT_STATUS_NO_MEMORY;
3442 status = cli_smb(talloc_tos(),
3443 cli,
3444 SMBgetatr, /* command. */
3445 0, /* additional_flags. */
3446 0, /* wct. */
3447 NULL, /* vwv. */
3448 talloc_get_size(bytes), /* num_bytes. */
3449 bytes, /* bytes. */
3450 NULL, /* result parent. */
3451 10, /* min_wct. */
3452 &return_wcount, /* return wcount. */
3453 &return_words, /* return wvw. */
3454 NULL, /* return byte count. */
3455 NULL); /* return bytes. */
3456 if (!NT_STATUS_IS_OK(status)) {
3457 return status;
3459 *pattr = PULL_LE_U16(return_words, 0);
3460 return status;
3463 static bool test_smb1_getatr(struct cli_state *cli)
3465 NTSTATUS status;
3466 bool retval = false;
3467 bool ok = false;
3468 uint16_t attrs = 0;
3470 /* Start clean. */
3471 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\getatrfile");
3473 /* Create a test file. */
3474 ok = smb1_create_testfile(cli, "\\BAD\\BAD\\getatrfile");
3475 if (!ok) {
3476 printf("%s:%d failed to create test file %s\n",
3477 __FILE__,
3478 __LINE__,
3479 "\\BAD\\BAD\\getatrfile");
3480 goto err;
3484 * We expect this to succeed, but get attributes of
3485 * the root directory.
3487 status = smb1_getatr(cli, "getatrfile", &attrs);
3488 if (!NT_STATUS_IS_OK(status)) {
3489 printf("%s:%d SMB1getatr of %s failed (%s)\n",
3490 __FILE__,
3491 __LINE__,
3492 "getatrfile",
3493 nt_errstr(status));
3494 goto err;
3496 if ((attrs & FILE_ATTRIBUTE_DIRECTORY) == 0) {
3497 printf("%s:%d error expected SMB1getatr of file %s "
3498 "to return directory attributes. Got 0x%x\n",
3499 __FILE__,
3500 __LINE__,
3501 "getatrfile",
3502 (unsigned int)attrs);
3503 goto err;
3507 * We expect this to succeed, but get attributes of
3508 * the root directory.
3510 status = smb1_getatr(cli, "\\BAD\\getatrfile", &attrs);
3511 if (!NT_STATUS_IS_OK(status)) {
3512 printf("%s:%d SMB1getatr of %s failed (%s)\n",
3513 __FILE__,
3514 __LINE__,
3515 "\\BAD\\getatrfile",
3516 nt_errstr(status));
3517 goto err;
3519 if ((attrs & FILE_ATTRIBUTE_DIRECTORY) == 0) {
3520 printf("%s:%d error expected SMB1getatr of file %s "
3521 "to return directory attributes. Got 0x%x\n",
3522 __FILE__,
3523 __LINE__,
3524 "\\BAD\\getatrfile",
3525 (unsigned int)attrs);
3526 goto err;
3530 * We expect this to succeed, and get attributes of
3531 * the testfile.
3533 status = smb1_getatr(cli, "\\BAD\\BAD\\getatrfile", &attrs);
3534 if (!NT_STATUS_IS_OK(status)) {
3535 printf("%s:%d SMB1getatr of %s failed (%s)\n",
3536 __FILE__,
3537 __LINE__,
3538 "\\BAD\\BAD\\getatrfile",
3539 nt_errstr(status));
3540 goto err;
3542 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
3543 printf("%s:%d error expected SMB1getatr of file %s "
3544 "to return non-directory attributes. Got 0x%x\n",
3545 __FILE__,
3546 __LINE__,
3547 "\\BAD\\BAD\\getatrfile",
3548 (unsigned int)attrs);
3549 goto err;
3552 retval = true;
3554 err:
3556 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\getatrfile");
3557 return retval;
3560 static NTSTATUS smb1_setatr(struct cli_state *cli,
3561 const char *path,
3562 uint16_t attr)
3564 uint16_t vwv[8] = { 0 };
3565 uint8_t *bytes = NULL;
3566 NTSTATUS status;
3568 PUSH_LE_U16(vwv, 0, attr);
3569 bytes = talloc_array(talloc_tos(), uint8_t, 1);
3570 if (bytes == NULL) {
3571 return NT_STATUS_NO_MEMORY;
3573 bytes[0] = 4;
3574 bytes = smb_bytes_push_str(bytes,
3575 smbXcli_conn_use_unicode(cli->conn),
3576 path,
3577 strlen(path)+1,
3578 NULL);
3579 if (bytes == NULL) {
3580 return NT_STATUS_NO_MEMORY;
3582 status = cli_smb(talloc_tos(),
3583 cli,
3584 SMBsetatr, /* command. */
3585 0, /* additional_flags. */
3586 8, /* wct. */
3587 vwv, /* vwv. */
3588 talloc_get_size(bytes), /* num_bytes. */
3589 bytes, /* bytes. */
3590 NULL, /* result parent. */
3591 0, /* min_wct. */
3592 NULL, /* return wcount. */
3593 NULL, /* return wvw. */
3594 NULL, /* return byte count. */
3595 NULL); /* return bytes. */
3596 if (!NT_STATUS_IS_OK(status)) {
3597 return status;
3599 return status;
3602 static bool test_smb1_setatr(struct cli_state *cli)
3604 NTSTATUS status;
3605 bool retval = false;
3606 bool ok = false;
3607 uint16_t file_attrs = 0;
3608 uint16_t orig_file_attrs = 0;
3610 /* Start clean. */
3611 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\setatrfile");
3613 /* Create a test file. */
3614 ok = smb1_create_testfile(cli, "\\BAD\\BAD\\setatrfile");
3615 if (!ok) {
3616 printf("%s:%d failed to create test file %s\n",
3617 __FILE__,
3618 __LINE__,
3619 "\\BAD\\BAD\\setatrfile");
3620 goto err;
3622 /* Get it's original attributes. */
3623 status = smb1_getatr(cli, "\\BAD\\BAD\\setatrfile", &orig_file_attrs);
3624 if (!NT_STATUS_IS_OK(status)) {
3625 printf("%s:%d SMB1getatr of %s failed (%s)\n",
3626 __FILE__,
3627 __LINE__,
3628 "\\BAD\\BAD\\setatrfile",
3629 nt_errstr(status));
3630 goto err;
3633 if (orig_file_attrs & FILE_ATTRIBUTE_SYSTEM) {
3634 printf("%s:%d orig_file_attrs of %s already has SYSTEM. "
3635 "Test cannot proceed.\n",
3636 __FILE__,
3637 __LINE__,
3638 "\\BAD\\BAD\\setatrfile");
3639 goto err;
3643 * Seems we can't set attrs on the root of a share,
3644 * even as Administrator.
3646 status = smb1_setatr(cli, "setatrfile", FILE_ATTRIBUTE_SYSTEM);
3647 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
3648 printf("%s:%d SMB1setatr of %s should get "
3649 "NT_STATUS_ACCESS_DENIED, got %s\n",
3650 __FILE__,
3651 __LINE__,
3652 "setatrfile",
3653 nt_errstr(status));
3654 goto err;
3658 * Seems we can't set attrs on the root of a share,
3659 * even as Administrator.
3661 status = smb1_setatr(cli, "\\BAD\\setatrfile", FILE_ATTRIBUTE_SYSTEM);
3662 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
3663 printf("%s:%d SMB1setatr of %s should get "
3664 "NT_STATUS_ACCESS_DENIED, got %s\n",
3665 __FILE__,
3666 __LINE__,
3667 "\\BAD\\setatrfile",
3668 nt_errstr(status));
3669 goto err;
3672 status = smb1_setatr(cli,
3673 "\\BAD\\BAD\\setatrfile",
3674 FILE_ATTRIBUTE_SYSTEM);
3675 if (!NT_STATUS_IS_OK(status)) {
3676 printf("%s:%d SMB1setatr of %s failed (%s)\n",
3677 __FILE__,
3678 __LINE__,
3679 "\\BAD\\BAD\\setatrfile",
3680 nt_errstr(status));
3681 goto err;
3683 status = smb1_getatr(cli, "\\BAD\\BAD\\setatrfile", &file_attrs);
3684 if (!NT_STATUS_IS_OK(status)) {
3685 printf("%s:%d SMB1getatr of %s failed (%s)\n",
3686 __FILE__,
3687 __LINE__,
3688 "\\BAD\\BAD\\setatrfile",
3689 nt_errstr(status));
3690 goto err;
3693 if (file_attrs != FILE_ATTRIBUTE_SYSTEM) {
3694 printf("%s:%d Failed to set SYSTEM attr on %s\n",
3695 __FILE__,
3696 __LINE__,
3697 "\\BAD\\BAD\\setatrfile");
3698 goto err;
3701 retval = true;
3703 err:
3705 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\setatrfile");
3706 return retval;
3709 static NTSTATUS smb1_chkpath(struct cli_state *cli,
3710 const char *path)
3712 uint8_t *bytes = NULL;
3713 NTSTATUS status;
3715 bytes = talloc_array(talloc_tos(), uint8_t, 1);
3716 if (bytes == NULL) {
3717 return NT_STATUS_NO_MEMORY;
3719 bytes[0] = 4;
3720 bytes = smb_bytes_push_str(bytes,
3721 smbXcli_conn_use_unicode(cli->conn),
3722 path,
3723 strlen(path)+1,
3724 NULL);
3725 if (bytes == NULL) {
3726 return NT_STATUS_NO_MEMORY;
3728 status = cli_smb(talloc_tos(),
3729 cli,
3730 SMBcheckpath, /* command. */
3731 0, /* additional_flags. */
3732 0, /* wct. */
3733 NULL, /* vwv. */
3734 talloc_get_size(bytes), /* num_bytes. */
3735 bytes, /* bytes. */
3736 NULL, /* result parent. */
3737 0, /* min_wct. */
3738 NULL, /* return wcount. */
3739 NULL, /* return wvw. */
3740 NULL, /* return byte count. */
3741 NULL); /* return bytes. */
3742 if (!NT_STATUS_IS_OK(status)) {
3743 return status;
3745 return status;
3748 static bool test_smb1_chkpath(struct cli_state *cli)
3750 NTSTATUS status;
3751 bool retval = false;
3752 bool ok = false;
3754 /* Start clean. */
3755 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\chkpathfile");
3757 /* Create a test file. */
3758 ok = smb1_create_testfile(cli, "\\BAD\\BAD\\chkpathfile");
3759 if (!ok) {
3760 printf("%s:%d failed to create test file %s\n",
3761 __FILE__,
3762 __LINE__,
3763 "\\BAD\\BAD\\chkpathfile");
3764 goto err;
3767 * Should succeed - "chkpathfile" maps to
3768 * directory "".
3770 status = smb1_chkpath(cli, "chkpathfile");
3771 if (!NT_STATUS_IS_OK(status)) {
3772 printf("%s:%d SMB1chkpath of %s failed (%s)\n",
3773 __FILE__,
3774 __LINE__,
3775 "chkpathfile",
3776 nt_errstr(status));
3777 goto err;
3781 * Should succeed - "\\BAD\\chkpathfile" maps to
3782 * directory "".
3784 status = smb1_chkpath(cli, "\\BAD\\chkpathfile");
3785 if (!NT_STATUS_IS_OK(status)) {
3786 printf("%s:%d SMB1chkpath of %s failed (%s)\n",
3787 __FILE__,
3788 __LINE__,
3789 "\\BAD\\chkpathfile",
3790 nt_errstr(status));
3791 goto err;
3795 * Should fail - "\\BAD\\BAD\\chkpathfile" maps to the
3796 * "\\BAD\\BAD\\chkpathfile", not a directory.
3798 status = smb1_chkpath(cli, "\\BAD\\BAD\\chkpathfile");
3799 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
3800 printf("%s:%d SMB1chkpath of %s should get "
3801 "NT_STATUS_NOT_A_DIRECTORY, got %s\n",
3802 __FILE__,
3803 __LINE__,
3804 "\\BAD\\BAD\\chkpathfile",
3805 nt_errstr(status));
3806 goto err;
3809 retval = true;
3811 err:
3813 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\chkpathfile");
3814 return retval;
3818 * "Raw" test of different SMB1 operations to a DFS share.
3819 * We must (mostly) use the lower level smb1cli_XXXX() interfaces,
3820 * not the cli_XXX() ones here as the ultimate goal is to fix our
3821 * cli_XXX() interfaces to work transparently over DFS.
3823 * So here, we're testing the server code, not the client code.
3825 * Passes cleanly against Windows.
3828 bool run_smb1_dfs_operations(int dummy)
3830 struct cli_state *cli = NULL;
3831 bool dfs_supported = false;
3832 bool retval = false;
3833 bool ok = false;
3835 printf("Starting SMB1-DFS-OPS\n");
3837 if (!torture_init_connection(&cli)) {
3838 return false;
3841 if (!torture_open_connection(&cli, 0)) {
3842 return false;
3845 /* Ensure this is a DFS share. */
3846 dfs_supported = smbXcli_conn_dfs_supported(cli->conn);
3847 if (!dfs_supported) {
3848 printf("Server %s does not support DFS\n",
3849 smbXcli_conn_remote_name(cli->conn));
3850 return false;
3852 dfs_supported = smbXcli_tcon_is_dfs_share(cli->smb1.tcon);
3853 if (!dfs_supported) {
3854 printf("Share %s does not support DFS\n",
3855 cli->share);
3856 return false;
3859 ok = test_smb1_unlink(cli);
3860 if (!ok) {
3861 goto err;
3864 ok = test_smb1_mkdir(cli);
3865 if (!ok) {
3866 goto err;
3869 ok = test_smb1_rmdir(cli);
3870 if (!ok) {
3871 goto err;
3874 ok = test_smb1_ntcreatex(cli);
3875 if (!ok) {
3876 goto err;
3879 ok = test_smb1_nttrans_create(cli);
3880 if (!ok) {
3881 goto err;
3884 ok = test_smb1_openx(cli);
3885 if (!ok) {
3886 goto err;
3889 ok = test_smb1_open(cli);
3890 if (!ok) {
3891 goto err;
3894 ok = test_smb1_create(cli);
3895 if (!ok) {
3896 goto err;
3899 ok = test_smb1_getatr(cli);
3900 if (!ok) {
3901 goto err;
3904 ok = test_smb1_setatr(cli);
3905 if (!ok) {
3906 goto err;
3909 ok = test_smb1_chkpath(cli);
3910 if (!ok) {
3911 goto err;
3914 retval = true;
3916 err:
3918 /* Delete anything we made. */
3919 (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\file");
3920 return retval;