Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : SMB1 DFS tests.
4 : Copyright (C) Jeremy Allison 2022.
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "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"
35 :
36 : extern fstring host, workgroup, share, password, username, myname;
37 : extern struct cli_credentials *torture_creds;
38 :
39 : /*
40 : * Open an SMB1 file readonly and return the create time.
41 : */
42 38 : static NTSTATUS get_smb1_crtime(struct cli_state *cli,
43 : const char *pathname,
44 : struct timespec *pcrtime)
45 : {
46 0 : NTSTATUS status;
47 38 : uint16_t fnum = 0;
48 38 : struct timespec crtime = {0};
49 :
50 : /*
51 : * Open the file.
52 : */
53 :
54 38 : status = smb1cli_ntcreatex(cli->conn,
55 38 : 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 38 : if (!NT_STATUS_IS_OK(status)) {
76 6 : return status;
77 : }
78 :
79 : /*
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.
85 : */
86 32 : 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 32 : if (NT_STATUS_IS_OK(status)) {
96 32 : *pcrtime = crtime;
97 : }
98 :
99 32 : (void)smb1cli_close(cli->conn,
100 32 : cli->timeout,
101 : cli->smb1.pid,
102 : cli->smb1.tcon,
103 : cli->smb1.session,
104 : fnum,
105 : 0); /* last_modified */
106 32 : return status;
107 : }
108 :
109 : /*
110 : * Check a crtime matches a given SMB1 path.
111 : */
112 30 : static bool smb1_crtime_matches(struct cli_state *cli,
113 : const char *match_pathname,
114 : struct timespec crtime_tomatch,
115 : const char *test_pathname)
116 : {
117 30 : struct timespec test_crtime = { 0 };
118 0 : NTSTATUS status;
119 30 : bool equal = false;
120 :
121 30 : status = get_smb1_crtime(cli,
122 : test_pathname,
123 : &test_crtime);
124 30 : if (!NT_STATUS_IS_OK(status)) {
125 2 : printf("%s: Failed to get crtime "
126 : "for %s, (%s)\n",
127 : __func__,
128 : test_pathname,
129 : nt_errstr(status));
130 2 : return false;
131 : }
132 28 : equal = (timespec_compare(&test_crtime, &crtime_tomatch) == 0);
133 28 : if (!equal) {
134 0 : struct timeval_buf test_buf;
135 0 : struct timeval_buf tomatch_buf;
136 0 : printf("%s: crtime mismatch "
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 0 : return false;
148 : }
149 28 : return true;
150 : }
151 :
152 : /*
153 : * Delete an SMB1 file on a DFS share.
154 : */
155 50 : static NTSTATUS smb1_dfs_delete(struct cli_state *cli,
156 : const char *pathname)
157 : {
158 0 : NTSTATUS status;
159 50 : uint16_t fnum = 0;
160 :
161 : /*
162 : * Open the file.
163 : */
164 :
165 50 : status = smb1cli_ntcreatex(cli->conn,
166 50 : 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 50 : if (!NT_STATUS_IS_OK(status)) {
186 38 : return status;
187 : }
188 :
189 : /*
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.
195 : */
196 : /*
197 : */
198 12 : status = cli_nt_delete_on_close(cli, fnum, 1);
199 12 : if (!NT_STATUS_IS_OK(status)) {
200 0 : return status;
201 : }
202 12 : return smb1cli_close(cli->conn,
203 12 : cli->timeout,
204 : cli->smb1.pid,
205 : cli->smb1.tcon,
206 : cli->smb1.session,
207 : fnum,
208 : 0); /* last_modified */
209 : }
210 :
211 : static void smb1_mv_done(struct tevent_req *subreq);
212 :
213 : struct smb1_mv_state {
214 : uint16_t vwv[1];
215 : };
216 :
217 0 : 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)
222 : {
223 0 : uint8_t *bytes = NULL;
224 0 : struct tevent_req *req = NULL;
225 0 : struct tevent_req *subreq = NULL;
226 0 : struct smb1_mv_state *state = NULL;
227 :
228 0 : req = tevent_req_create(mem_ctx,
229 : &state,
230 : struct smb1_mv_state);
231 0 : if (req == NULL) {
232 0 : return NULL;
233 : }
234 :
235 0 : PUSH_LE_U16(state->vwv,
236 : 0,
237 : FILE_ATTRIBUTE_SYSTEM |
238 : FILE_ATTRIBUTE_HIDDEN |
239 : FILE_ATTRIBUTE_DIRECTORY);
240 :
241 0 : bytes = talloc_array(state, uint8_t, 1);
242 0 : if (tevent_req_nomem(bytes, req)) {
243 0 : return tevent_req_post(req, ev);
244 : }
245 0 : bytes[0] = 4;
246 0 : bytes = smb_bytes_push_str(bytes,
247 0 : smbXcli_conn_use_unicode(cli->conn),
248 : src_dfs_name,
249 0 : strlen(src_dfs_name)+1,
250 : NULL);
251 0 : if (tevent_req_nomem(bytes, req)) {
252 0 : return tevent_req_post(req, ev);
253 : }
254 :
255 0 : bytes = talloc_realloc(state,
256 : bytes,
257 : uint8_t,
258 : talloc_get_size(bytes)+1);
259 0 : if (tevent_req_nomem(bytes, req)) {
260 0 : return tevent_req_post(req, ev);
261 : }
262 :
263 0 : bytes[talloc_get_size(bytes)-1] = 4;
264 0 : bytes = smb_bytes_push_str(bytes,
265 0 : smbXcli_conn_use_unicode(cli->conn),
266 : target_name,
267 0 : strlen(target_name)+1,
268 : NULL);
269 0 : if (tevent_req_nomem(bytes, req)) {
270 0 : return tevent_req_post(req, ev);
271 : }
272 :
273 0 : subreq = cli_smb_send(state,
274 : ev,
275 : cli,
276 : SMBmv,
277 : 0, /* additional_flags */
278 : 0, /* additional_flags2 */
279 : 1,
280 0 : state->vwv,
281 0 : talloc_get_size(bytes),
282 : bytes);
283 0 : if (tevent_req_nomem(subreq, req)) {
284 0 : return tevent_req_post(req, ev);
285 : }
286 0 : tevent_req_set_callback(subreq, smb1_mv_done, req);
287 0 : return req;
288 : }
289 :
290 0 : static void smb1_mv_done(struct tevent_req *subreq)
291 : {
292 0 : NTSTATUS status = cli_smb_recv(subreq,
293 : NULL,
294 : NULL,
295 : 0,
296 : NULL,
297 : NULL,
298 : NULL,
299 : NULL);
300 0 : tevent_req_simple_finish_ntstatus(subreq,
301 : status);
302 0 : }
303 :
304 0 : static NTSTATUS smb1_mv_recv(struct tevent_req *req)
305 : {
306 0 : return tevent_req_simple_recv_ntstatus(req);
307 : }
308 :
309 : /*
310 : * Rename an SMB1 file on a DFS share. SMBmv version.
311 : */
312 0 : static NTSTATUS smb1_mv(struct cli_state *cli,
313 : const char *src_dfs_name,
314 : const char *target_name)
315 : {
316 0 : TALLOC_CTX *frame = NULL;
317 0 : struct tevent_context *ev;
318 0 : struct tevent_req *req;
319 0 : NTSTATUS status;
320 :
321 0 : frame = talloc_stackframe();
322 :
323 0 : ev = samba_tevent_context_init(frame);
324 0 : if (ev == NULL) {
325 0 : status = NT_STATUS_NO_MEMORY;
326 0 : goto fail;
327 : }
328 :
329 0 : req = smb1_mv_send(frame,
330 : ev,
331 : cli,
332 : src_dfs_name,
333 : target_name);
334 0 : if (req == NULL) {
335 0 : status = NT_STATUS_NO_MEMORY;
336 0 : goto fail;
337 : }
338 :
339 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
340 0 : goto fail;
341 : }
342 :
343 0 : status = smb1_mv_recv(req);
344 :
345 0 : fail:
346 :
347 0 : TALLOC_FREE(frame);
348 0 : return status;
349 : }
350 :
351 0 : static bool test_smb1_mv(struct cli_state *cli,
352 : const char *src_dfs_name)
353 : {
354 0 : struct timespec test_timespec = { 0 };
355 0 : NTSTATUS status;
356 :
357 0 : status = smb1_mv(cli,
358 : src_dfs_name,
359 : "BAD\\BAD\\renamed_file");
360 0 : if (!NT_STATUS_IS_OK(status)) {
361 0 : 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 0 : return false;
369 : }
370 :
371 : /* Ensure we did rename. */
372 0 : status = get_smb1_crtime(cli,
373 : "BAD\\BAD\\renamed_file",
374 : &test_timespec);
375 0 : if (!NT_STATUS_IS_OK(status)) {
376 0 : 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 0 : return false;
383 : }
384 :
385 : /* Put it back. */
386 0 : status = smb1_mv(cli,
387 : "BAD\\BAD\\renamed_file",
388 : src_dfs_name);
389 0 : if (!NT_STATUS_IS_OK(status)) {
390 0 : 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 0 : return false;
398 : }
399 :
400 : /* Ensure we did put it back. */
401 0 : status = get_smb1_crtime(cli,
402 : src_dfs_name,
403 : &test_timespec);
404 0 : if (!NT_STATUS_IS_OK(status)) {
405 0 : 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 0 : return false;
412 : }
413 :
414 : /* Try with a non-DFS name. */
415 0 : status = smb1_mv(cli,
416 : src_dfs_name,
417 : "renamed_file");
418 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD)) {
419 : /* Fails I think as target becomes "" on server. */
420 0 : 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 0 : return false;
428 : }
429 :
430 : /* Try with a non-DFS name. */
431 0 : status = smb1_mv(cli,
432 : src_dfs_name,
433 : "BAD\\renamed_file");
434 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD)) {
435 : /* Fails I think as target becomes "" on server. */
436 0 : 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 0 : return false;
444 : }
445 0 : return true;
446 : }
447 :
448 : static void smb1_setpathinfo_done(struct tevent_req *subreq);
449 :
450 : struct smb1_setpathinfo_state {
451 : uint16_t setup;
452 : uint8_t *param;
453 : uint8_t *data;
454 : };
455 :
456 0 : 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)
462 : {
463 0 : struct tevent_req *req = NULL;
464 0 : struct tevent_req *subreq = NULL;
465 0 : struct smb1_setpathinfo_state *state = NULL;
466 0 : smb_ucs2_t *converted_str = NULL;
467 0 : size_t converted_size_bytes = 0;
468 0 : bool ok = false;
469 :
470 0 : req = tevent_req_create(mem_ctx,
471 : &state,
472 : struct smb1_setpathinfo_state);
473 0 : if (req == NULL) {
474 0 : return NULL;
475 : }
476 :
477 0 : PUSH_LE_U16(&state->setup, 0, TRANSACT2_SETPATHINFO);
478 :
479 0 : state->param = talloc_zero_array(state, uint8_t, 6);
480 0 : if (tevent_req_nomem(state->param, req)) {
481 0 : return tevent_req_post(req, ev);
482 : }
483 0 : PUSH_LE_U16(state->param, 0, info_level);
484 :
485 0 : state->param = trans2_bytes_push_str(state->param,
486 0 : smbXcli_conn_use_unicode(cli->conn),
487 : src_dfs_name,
488 0 : strlen(src_dfs_name)+1,
489 : NULL);
490 0 : if (tevent_req_nomem(state->param, req)) {
491 0 : return tevent_req_post(req, ev);
492 : }
493 :
494 0 : ok = push_ucs2_talloc(state,
495 : &converted_str,
496 : target_name,
497 : &converted_size_bytes);
498 0 : if (!ok) {
499 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
500 0 : return tevent_req_post(req, ev);
501 : }
502 :
503 : /*
504 : * W2K8 insists the dest name is not null
505 : * terminated. Remove the last 2 zero bytes
506 : * and reduce the name length.
507 : */
508 :
509 0 : if (converted_size_bytes < 2) {
510 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
511 0 : return tevent_req_post(req, ev);
512 : }
513 0 : converted_size_bytes -= 2;
514 :
515 0 : state->data = talloc_zero_array(state,
516 : uint8_t,
517 : 12 + converted_size_bytes);
518 0 : if (tevent_req_nomem(state->data, req)) {
519 0 : return tevent_req_post(req, ev);
520 : }
521 :
522 0 : SIVAL(state->data, 8, converted_size_bytes);
523 0 : memcpy(state->data + 12, converted_str, converted_size_bytes);
524 :
525 0 : 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 0 : &state->setup,/* setup. */
535 : 1,/* num setup uint16_t words. */
536 : 0,/* max returned setup. */
537 0 : state->param,/* param. */
538 0 : talloc_get_size(state->param),/* num param. */
539 : 2,/* max returned param. */
540 0 : state->data,/* data. */
541 0 : talloc_get_size(state->data),/* num data. */
542 : 0);/* max returned data. */
543 :
544 0 : if (tevent_req_nomem(subreq, req)) {
545 0 : return tevent_req_post(req, ev);
546 : }
547 0 : tevent_req_set_callback(subreq, smb1_setpathinfo_done, req);
548 0 : return req;
549 : }
550 :
551 0 : static void smb1_setpathinfo_done(struct tevent_req *subreq)
552 : {
553 0 : NTSTATUS status = cli_trans_recv(subreq,
554 : NULL,
555 : NULL,
556 : NULL,
557 : 0,
558 : NULL,
559 : NULL,
560 : 0,
561 : NULL,
562 : NULL,
563 : 0,
564 : NULL);
565 0 : tevent_req_simple_finish_ntstatus(subreq,
566 : status);
567 0 : }
568 :
569 0 : static NTSTATUS smb1_setpathinfo_recv(struct tevent_req *req)
570 : {
571 0 : return tevent_req_simple_recv_ntstatus(req);
572 : }
573 :
574 : /*
575 : * Rename or hardlink an SMB1 file on a DFS share. SMB1 setpathinfo
576 : * (pathnames only) version.
577 : */
578 0 : static NTSTATUS smb1_setpathinfo(struct cli_state *cli,
579 : const char *src_dfs_name,
580 : const char *target_name,
581 : uint16_t info_level)
582 : {
583 0 : TALLOC_CTX *frame = NULL;
584 0 : struct tevent_context *ev;
585 0 : struct tevent_req *req;
586 0 : NTSTATUS status;
587 :
588 0 : frame = talloc_stackframe();
589 :
590 0 : ev = samba_tevent_context_init(frame);
591 0 : if (ev == NULL) {
592 0 : status = NT_STATUS_NO_MEMORY;
593 0 : goto fail;
594 : }
595 :
596 0 : req = smb1_setpathinfo_send(frame,
597 : ev,
598 : cli,
599 : src_dfs_name,
600 : target_name,
601 : info_level);
602 0 : if (req == NULL) {
603 0 : status = NT_STATUS_NO_MEMORY;
604 0 : goto fail;
605 : }
606 :
607 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
608 0 : goto fail;
609 : }
610 :
611 0 : status = smb1_setpathinfo_recv(req);
612 :
613 0 : fail:
614 :
615 0 : TALLOC_FREE(frame);
616 0 : return status;
617 : }
618 :
619 0 : static NTSTATUS smb1_setpathinfo_rename(struct cli_state *cli,
620 : const char *src_dfs_name,
621 : const char *target_name)
622 : {
623 0 : return smb1_setpathinfo(cli,
624 : src_dfs_name,
625 : target_name,
626 : SMB_FILE_RENAME_INFORMATION);
627 : }
628 :
629 0 : static bool test_smb1_setpathinfo_rename(struct cli_state *cli,
630 : const char *src_dfs_name)
631 : {
632 0 : struct timespec test_crtime = { 0 };
633 0 : NTSTATUS status;
634 0 : const char *putback_path = NULL;
635 :
636 : /*
637 : * On Windows, setpathinfo rename where the target contains
638 : * any directory separator returns STATUS_NOT_SUPPORTED.
639 : *
640 : * MS-SMB behavior note: <133> Section 3.3.5.10.6:
641 : *
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."
645 : */
646 0 : status = smb1_setpathinfo_rename(cli,
647 : src_dfs_name,
648 : "BAD\\BAD\\renamed_file");
649 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
650 0 : 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 0 : return false;
658 : }
659 :
660 : /* Try with a non-DFS name. */
661 0 : status = smb1_setpathinfo_rename(cli,
662 : src_dfs_name,
663 : "renamed_file");
664 0 : if (!NT_STATUS_IS_OK(status)) {
665 0 : 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 0 : return false;
673 : }
674 :
675 : /* Ensure we did rename. */
676 0 : status = get_smb1_crtime(cli,
677 : "BAD\\BAD\\renamed_file",
678 : &test_crtime);
679 0 : if (!NT_STATUS_IS_OK(status)) {
680 0 : 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 0 : return false;
687 : }
688 :
689 : /*
690 : * To put it back we need to reverse the DFS-ness of src
691 : * and destination paths.
692 : */
693 0 : putback_path = strrchr(src_dfs_name, '\\');
694 0 : if (putback_path == NULL) {
695 0 : printf("%s:%d non DFS path %s passed. Internal error\n",
696 : __FILE__,
697 : __LINE__,
698 : src_dfs_name);
699 0 : return false;
700 : }
701 : /* Walk past the last '\\' */
702 0 : putback_path++;
703 :
704 : /* Put it back. */
705 0 : status = smb1_setpathinfo_rename(cli,
706 : "BAD\\BAD\\renamed_file",
707 : putback_path);
708 0 : if (!NT_STATUS_IS_OK(status)) {
709 0 : 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 0 : return false;
717 : }
718 :
719 : /* Ensure we did rename. */
720 0 : status = get_smb1_crtime(cli,
721 : src_dfs_name,
722 : &test_crtime);
723 0 : if (!NT_STATUS_IS_OK(status)) {
724 0 : 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 0 : return false;
731 : }
732 :
733 0 : return true;
734 : }
735 :
736 0 : static NTSTATUS smb1_setpathinfo_hardlink(struct cli_state *cli,
737 : const char *src_dfs_name,
738 : const char *target_name)
739 : {
740 0 : return smb1_setpathinfo(cli,
741 : src_dfs_name,
742 : target_name,
743 : SMB_FILE_LINK_INFORMATION);
744 : }
745 :
746 0 : static bool test_smb1_setpathinfo_hardlink(struct cli_state *cli,
747 : const char *src_dfs_name)
748 : {
749 0 : NTSTATUS status;
750 :
751 : /*
752 : * On Windows, setpathinfo rename where the target contains
753 : * any directory separator returns STATUS_NOT_SUPPORTED.
754 : *
755 : * MS-SMB behavior note: <133> Section 3.3.5.10.6:
756 : *
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."
760 : *
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.
766 : */
767 0 : status = smb1_setpathinfo_hardlink(cli,
768 : src_dfs_name,
769 : "BAD\\BAD\\hlink");
770 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
771 0 : 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 0 : return false;
779 : }
780 :
781 : /* Try with a non-DFS name. */
782 : /*
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.
787 : */
788 0 : status = smb1_setpathinfo_hardlink(cli,
789 : src_dfs_name,
790 : "hlink");
791 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
792 0 : 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 0 : return false;
800 : }
801 0 : return true;
802 : }
803 :
804 : static void smb1_ntrename_done(struct tevent_req *subreq);
805 :
806 : struct smb1_ntrename_state {
807 : uint16_t vwv[4];
808 : };
809 :
810 0 : 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)
816 : {
817 0 : struct tevent_req *req = NULL;
818 0 : struct tevent_req *subreq = NULL;
819 0 : struct smb1_ntrename_state *state = NULL;
820 0 : uint8_t *bytes = NULL;
821 :
822 0 : req = tevent_req_create(mem_ctx,
823 : &state,
824 : struct smb1_ntrename_state);
825 0 : if (req == NULL) {
826 0 : return NULL;
827 : }
828 :
829 0 : PUSH_LE_U16(state->vwv,
830 : 0,
831 : FILE_ATTRIBUTE_SYSTEM |
832 : FILE_ATTRIBUTE_HIDDEN |
833 : FILE_ATTRIBUTE_DIRECTORY);
834 0 : PUSH_LE_U16(state->vwv, 2, rename_flag);
835 :
836 0 : bytes = talloc_array(state, uint8_t, 1);
837 0 : if (tevent_req_nomem(bytes, req)) {
838 0 : return tevent_req_post(req, ev);
839 : }
840 :
841 0 : bytes[0] = 4;
842 0 : bytes = smb_bytes_push_str(bytes,
843 0 : smbXcli_conn_use_unicode(cli->conn),
844 : src_dfs_name,
845 0 : strlen(src_dfs_name)+1,
846 : NULL);
847 0 : if (tevent_req_nomem(bytes, req)) {
848 0 : return tevent_req_post(req, ev);
849 : }
850 0 : bytes = talloc_realloc(state,
851 : bytes,
852 : uint8_t,
853 : talloc_get_size(bytes)+1);
854 0 : if (tevent_req_nomem(bytes, req)) {
855 0 : return tevent_req_post(req, ev);
856 : }
857 :
858 0 : bytes[talloc_get_size(bytes)-1] = 4;
859 0 : bytes = smb_bytes_push_str(bytes,
860 0 : smbXcli_conn_use_unicode(cli->conn),
861 : target_name,
862 0 : strlen(target_name)+1,
863 : NULL);
864 0 : if (tevent_req_nomem(bytes, req)) {
865 0 : return tevent_req_post(req, ev);
866 : }
867 :
868 0 : subreq = cli_smb_send(state,
869 : ev,
870 : cli,
871 : SMBntrename,
872 : 0, /* additional_flags */
873 : 0, /* additional_flags2 */
874 : 4,
875 0 : state->vwv,
876 0 : talloc_get_size(bytes),
877 : bytes);
878 0 : if (tevent_req_nomem(subreq, req)) {
879 0 : return tevent_req_post(req, ev);
880 : }
881 0 : tevent_req_set_callback(subreq, smb1_ntrename_done, req);
882 0 : return req;
883 : }
884 :
885 0 : static void smb1_ntrename_done(struct tevent_req *subreq)
886 : {
887 0 : NTSTATUS status = cli_smb_recv(subreq,
888 : NULL,
889 : NULL,
890 : 0,
891 : NULL,
892 : NULL,
893 : NULL,
894 : NULL);
895 0 : tevent_req_simple_finish_ntstatus(subreq, status);
896 0 : }
897 :
898 0 : static NTSTATUS smb1_ntrename_recv(struct tevent_req *req)
899 : {
900 0 : return tevent_req_simple_recv_ntstatus(req);
901 : }
902 :
903 : /*
904 : * Rename or hardlink an SMB1 file on a DFS share. SMB1 ntrename version.
905 : * (pathnames only).
906 : */
907 0 : static NTSTATUS smb1_ntrename(struct cli_state *cli,
908 : const char *src_dfs_name,
909 : const char *target_name,
910 : uint16_t rename_flag)
911 : {
912 0 : TALLOC_CTX *frame = NULL;
913 0 : struct tevent_context *ev;
914 0 : struct tevent_req *req;
915 0 : NTSTATUS status;
916 :
917 0 : frame = talloc_stackframe();
918 :
919 0 : ev = samba_tevent_context_init(frame);
920 0 : if (ev == NULL) {
921 0 : status = NT_STATUS_NO_MEMORY;
922 0 : goto fail;
923 : }
924 :
925 0 : req = smb1_ntrename_send(frame,
926 : ev,
927 : cli,
928 : src_dfs_name,
929 : target_name,
930 : rename_flag);
931 0 : if (req == NULL) {
932 0 : status = NT_STATUS_NO_MEMORY;
933 0 : goto fail;
934 : }
935 :
936 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
937 0 : goto fail;
938 : }
939 :
940 0 : status = smb1_ntrename_recv(req);
941 :
942 0 : fail:
943 :
944 0 : TALLOC_FREE(frame);
945 0 : return status;
946 : }
947 : /*
948 : * Rename an SMB1 file on a DFS share. SMB1 ntrename version.
949 : */
950 0 : static NTSTATUS smb1_ntrename_rename(struct cli_state *cli,
951 : const char *src_dfs_name,
952 : const char *target_name)
953 : {
954 0 : return smb1_ntrename(cli,
955 : src_dfs_name,
956 : target_name,
957 : RENAME_FLAG_RENAME);
958 : }
959 :
960 :
961 0 : static bool test_smb1_ntrename_rename(struct cli_state *cli,
962 : const char *src_dfs_name)
963 : {
964 0 : struct timespec test_crtime = { 0 };
965 0 : NTSTATUS status;
966 :
967 : /* Try with a non-DFS name. */
968 0 : status = smb1_ntrename_rename(cli,
969 : src_dfs_name,
970 : "renamed_file");
971 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD)) {
972 : /* Fails I think as target becomes "" on server. */
973 0 : 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 0 : return false;
981 : }
982 :
983 0 : status = smb1_ntrename_rename(cli,
984 : src_dfs_name,
985 : "BAD\\BAD\\renamed_file");
986 0 : if (!NT_STATUS_IS_OK(status)) {
987 0 : 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 0 : return false;
995 : }
996 :
997 : /* Ensure we did rename. */
998 0 : status = get_smb1_crtime(cli,
999 : "BAD\\BAD\\renamed_file",
1000 : &test_crtime);
1001 0 : if (!NT_STATUS_IS_OK(status)) {
1002 0 : 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 0 : return false;
1009 : }
1010 :
1011 : /* Put it back. */
1012 0 : status = smb1_ntrename_rename(cli,
1013 : "BAD\\BAD\\renamed_file",
1014 : src_dfs_name);
1015 0 : if (!NT_STATUS_IS_OK(status)) {
1016 0 : 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 0 : return false;
1024 : }
1025 :
1026 : /* Ensure we did rename. */
1027 0 : status = get_smb1_crtime(cli,
1028 : src_dfs_name,
1029 : &test_crtime);
1030 0 : if (!NT_STATUS_IS_OK(status)) {
1031 0 : 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 0 : return false;
1038 : }
1039 :
1040 0 : return true;
1041 : }
1042 :
1043 : /*
1044 : * Hard link an SMB1 file on a DFS share. SMB1 ntrename version.
1045 : */
1046 0 : static NTSTATUS smb1_ntrename_hardlink(struct cli_state *cli,
1047 : const char *src_dfs_name,
1048 : const char *target_name)
1049 : {
1050 0 : return smb1_ntrename(cli,
1051 : src_dfs_name,
1052 : target_name,
1053 : RENAME_FLAG_HARD_LINK);
1054 : }
1055 :
1056 0 : static bool test_smb1_ntrename_hardlink(struct cli_state *cli,
1057 : const char *src_dfs_name)
1058 : {
1059 0 : struct timespec test_crtime = { 0 };
1060 0 : NTSTATUS status;
1061 0 : bool retval = false;
1062 :
1063 : /* Try with a non-DFS name. */
1064 0 : status = smb1_ntrename_hardlink(cli,
1065 : src_dfs_name,
1066 : "hlink");
1067 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD)) {
1068 : /* Fails I think as target becomes "" on server. */
1069 0 : 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 0 : return false;
1077 : }
1078 :
1079 0 : status = smb1_ntrename_hardlink(cli,
1080 : src_dfs_name,
1081 : "BAD\\BAD\\hlink");
1082 0 : if (!NT_STATUS_IS_OK(status)) {
1083 0 : 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 0 : goto out;
1091 : }
1092 :
1093 : /* Ensure we did hardlink. */
1094 0 : status = get_smb1_crtime(cli,
1095 : "BAD\\BAD\\hlink",
1096 : &test_crtime);
1097 0 : if (!NT_STATUS_IS_OK(status)) {
1098 0 : 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 0 : goto out;
1105 : }
1106 :
1107 0 : retval = smb1_crtime_matches(cli,
1108 : "BAD\\BAD\\hlink",
1109 : test_crtime,
1110 : src_dfs_name);
1111 0 : if (!retval) {
1112 0 : 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 0 : goto out;
1119 : }
1120 :
1121 0 : out:
1122 :
1123 : /* Remove the hardlink to clean up. */
1124 0 : (void)smb1_dfs_delete(cli, "BAD\\BAD\\hlink");
1125 0 : return retval;
1126 : }
1127 :
1128 : static void smb1_setfileinfo_done(struct tevent_req *subreq);
1129 :
1130 : struct smb1_setfileinfo_state {
1131 : uint16_t setup;
1132 : uint8_t param[6];
1133 : uint8_t *data;
1134 : };
1135 :
1136 0 : 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)
1142 : {
1143 0 : struct tevent_req *req = NULL;
1144 0 : struct tevent_req *subreq = NULL;
1145 0 : struct smb1_setfileinfo_state *state = NULL;
1146 0 : smb_ucs2_t *converted_str = NULL;
1147 0 : size_t converted_size_bytes = 0;
1148 0 : bool ok = false;
1149 :
1150 0 : req = tevent_req_create(mem_ctx,
1151 : &state,
1152 : struct smb1_setfileinfo_state);
1153 0 : if (req == NULL) {
1154 0 : return NULL;
1155 : }
1156 :
1157 0 : PUSH_LE_U16(&state->setup, 0, TRANSACT2_SETPATHINFO);
1158 :
1159 0 : PUSH_LE_U16(state->param, 0, fnum);
1160 0 : PUSH_LE_U16(state->param, 2, info_level);
1161 :
1162 0 : ok = push_ucs2_talloc(state,
1163 : &converted_str,
1164 : target_name,
1165 : &converted_size_bytes);
1166 0 : if (!ok) {
1167 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1168 0 : return tevent_req_post(req, ev);
1169 : }
1170 :
1171 : /*
1172 : * W2K8 insists the dest name is not null
1173 : * terminated. Remove the last 2 zero bytes
1174 : * and reduce the name length.
1175 : */
1176 :
1177 0 : if (converted_size_bytes < 2) {
1178 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1179 0 : return tevent_req_post(req, ev);
1180 : }
1181 0 : converted_size_bytes -= 2;
1182 :
1183 0 : state->data = talloc_zero_array(state,
1184 : uint8_t,
1185 : 12 + converted_size_bytes);
1186 0 : if (tevent_req_nomem(state->data, req)) {
1187 0 : return tevent_req_post(req, ev);
1188 : }
1189 :
1190 0 : SIVAL(state->data, 8, converted_size_bytes);
1191 0 : memcpy(state->data + 12, converted_str, converted_size_bytes);
1192 :
1193 0 : 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 0 : &state->setup,/* setup. */
1203 : 1,/* num setup uint16_t words. */
1204 : 0,/* max returned setup. */
1205 0 : state->param,/* param. */
1206 : 6,/* num param. */
1207 : 2,/* max returned param. */
1208 0 : state->data,/* data. */
1209 0 : talloc_get_size(state->data),/* num data. */
1210 : 0);/* max returned data. */
1211 :
1212 0 : if (tevent_req_nomem(subreq, req)) {
1213 0 : return tevent_req_post(req, ev);
1214 : }
1215 0 : tevent_req_set_callback(subreq, smb1_setfileinfo_done, req);
1216 0 : return req;
1217 : }
1218 :
1219 0 : static void smb1_setfileinfo_done(struct tevent_req *subreq)
1220 : {
1221 0 : NTSTATUS status = cli_trans_recv(subreq,
1222 : NULL,
1223 : NULL,
1224 : NULL,
1225 : 0,
1226 : NULL,
1227 : NULL,
1228 : 0,
1229 : NULL,
1230 : NULL,
1231 : 0,
1232 : NULL);
1233 0 : tevent_req_simple_finish_ntstatus(subreq,
1234 : status);
1235 0 : }
1236 :
1237 0 : static NTSTATUS smb1_setfileinfo_recv(struct tevent_req *req)
1238 : {
1239 0 : return tevent_req_simple_recv_ntstatus(req);
1240 : }
1241 :
1242 : /*
1243 : * Rename or hardlink an SMB1 file on a DFS share.
1244 : * setfileinfo (file handle + target pathname) version.
1245 : */
1246 0 : static NTSTATUS smb1_setfileinfo(struct cli_state *cli,
1247 : uint16_t fnum,
1248 : const char *target_name,
1249 : uint16_t info_level)
1250 : {
1251 0 : TALLOC_CTX *frame = NULL;
1252 0 : struct tevent_context *ev;
1253 0 : struct tevent_req *req;
1254 0 : NTSTATUS status;
1255 :
1256 0 : frame = talloc_stackframe();
1257 :
1258 0 : ev = samba_tevent_context_init(frame);
1259 0 : if (ev == NULL) {
1260 0 : status = NT_STATUS_NO_MEMORY;
1261 0 : goto fail;
1262 : }
1263 :
1264 0 : req = smb1_setfileinfo_send(frame,
1265 : ev,
1266 : cli,
1267 : fnum,
1268 : target_name,
1269 : info_level);
1270 0 : if (req == NULL) {
1271 0 : status = NT_STATUS_NO_MEMORY;
1272 0 : goto fail;
1273 : }
1274 :
1275 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1276 0 : goto fail;
1277 : }
1278 :
1279 0 : status = smb1_setfileinfo_recv(req);
1280 :
1281 0 : fail:
1282 :
1283 0 : TALLOC_FREE(frame);
1284 0 : return status;
1285 : }
1286 :
1287 0 : static NTSTATUS smb1_setfileinfo_rename(struct cli_state *cli,
1288 : uint16_t fnum,
1289 : const char *target_name)
1290 : {
1291 0 : return smb1_setfileinfo(cli,
1292 : fnum,
1293 : target_name,
1294 : SMB_FILE_RENAME_INFORMATION);
1295 : }
1296 :
1297 : /*
1298 : * On Windows, rename using a file handle as source
1299 : * is not supported.
1300 : */
1301 :
1302 0 : static bool test_smb1_setfileinfo_rename(struct cli_state *cli,
1303 : const char *src_dfs_name)
1304 : {
1305 0 : uint16_t fnum = (uint16_t)-1;
1306 0 : NTSTATUS status;
1307 0 : bool retval = false;
1308 :
1309 : /* First open the source file. */
1310 0 : status = smb1cli_ntcreatex(cli->conn,
1311 0 : 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 0 : if (!NT_STATUS_IS_OK(status)) {
1331 0 : printf("%s:%d failed to open %s, %s\n",
1332 : __FILE__,
1333 : __LINE__,
1334 : src_dfs_name,
1335 : nt_errstr(status));
1336 0 : goto out;
1337 : }
1338 :
1339 : /*
1340 : * On Windows rename given a file handle returns
1341 : * NT_STATUS_UNSUCCESSFUL (not documented in MS-SMB).
1342 : */
1343 :
1344 0 : status = smb1_setfileinfo_rename(cli,
1345 : fnum,
1346 : "BAD\\BAD\\renamed_file");
1347 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1348 0 : 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 0 : goto out;
1356 : }
1357 :
1358 : /* Try with a non-DFS name - still gets NT_STATUS_UNSUCCESSFUL. */
1359 0 : status = smb1_setfileinfo_rename(cli,
1360 : fnum,
1361 : "renamed_file");
1362 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1363 0 : 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 0 : goto out;
1371 : }
1372 :
1373 0 : retval = true;
1374 :
1375 0 : out:
1376 :
1377 0 : if (fnum != (uint16_t)-1) {
1378 0 : (void)smb1cli_close(cli->conn,
1379 0 : cli->timeout,
1380 : cli->smb1.pid,
1381 : cli->smb1.tcon,
1382 : cli->smb1.session,
1383 : fnum,
1384 : 0); /* last_modified */
1385 : }
1386 :
1387 0 : (void)smb1_dfs_delete(cli, "BAD\\BAD\\renamed_file");
1388 0 : return retval;
1389 : }
1390 :
1391 :
1392 0 : static NTSTATUS smb1_setfileinfo_hardlink(struct cli_state *cli,
1393 : uint16_t fnum,
1394 : const char *target_name)
1395 : {
1396 0 : return smb1_setfileinfo(cli,
1397 : fnum,
1398 : target_name,
1399 : SMB_FILE_LINK_INFORMATION);
1400 : }
1401 :
1402 : /*
1403 : * On Windows, hardlink using a file handle as source
1404 : * is not supported.
1405 : */
1406 :
1407 0 : static bool test_smb1_setfileinfo_hardlink(struct cli_state *cli,
1408 : const char *src_dfs_name)
1409 : {
1410 0 : uint16_t fnum = (uint16_t)-1;
1411 0 : NTSTATUS status;
1412 0 : bool retval = false;
1413 :
1414 : /* First open the source file. */
1415 0 : status = smb1cli_ntcreatex(cli->conn,
1416 0 : 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 0 : if (!NT_STATUS_IS_OK(status)) {
1436 0 : printf("%s:%d failed to open %s, %s\n",
1437 : __FILE__,
1438 : __LINE__,
1439 : src_dfs_name,
1440 : nt_errstr(status));
1441 0 : goto out;
1442 : }
1443 :
1444 : /*
1445 : * On Windows hardlink given a file handle returns
1446 : * NT_STATUS_UNSUCCESSFUL (not documented in MS-SMB).
1447 : */
1448 :
1449 0 : status = smb1_setfileinfo_hardlink(cli,
1450 : fnum,
1451 : "BAD\\BAD\\hlink");
1452 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1453 0 : 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 0 : goto out;
1461 : }
1462 :
1463 : /* Try with a non-DFS name - still gets NT_STATUS_UNSUCCESSFUL. */
1464 0 : status = smb1_setfileinfo_hardlink(cli,
1465 : fnum,
1466 : "hlink");
1467 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1468 0 : 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 0 : goto out;
1476 : }
1477 :
1478 0 : retval = true;
1479 :
1480 0 : out:
1481 :
1482 0 : if (fnum != (uint16_t)-1) {
1483 0 : (void)smb1cli_close(cli->conn,
1484 0 : cli->timeout,
1485 : cli->smb1.pid,
1486 : cli->smb1.tcon,
1487 : cli->smb1.session,
1488 : fnum,
1489 : 0); /* last_modified */
1490 : }
1491 :
1492 0 : (void)smb1_dfs_delete(cli, "BAD\\BAD\\hlink");
1493 0 : return retval;
1494 : }
1495 :
1496 : /*
1497 : * According to:
1498 :
1499 : * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/dc9978d7-6299-4c5a-a22d-a039cdc716ea
1500 : *
1501 : * (Characters " \ / [ ] : | < > + = ; , * ?,
1502 : * and control characters in range 0x00 through
1503 : * 0x1F, inclusive, are illegal in a share name)
1504 : *
1505 : * But Windows server only checks in DFS sharenames ':'. All other
1506 : * share names are allowed.
1507 : */
1508 :
1509 0 : static bool test_smb1_dfs_sharenames(struct cli_state *cli,
1510 : const char *dfs_root_share_name,
1511 : struct timespec root_crtime)
1512 : {
1513 0 : char test_path[20];
1514 0 : const char *test_str = "/[]:|<>+=;,*?";
1515 0 : const char *p;
1516 0 : unsigned int i;
1517 0 : bool crtime_matched = false;
1518 :
1519 : /* Setup template pathname. */
1520 0 : memcpy(test_path, "\\SERVER\\X", 10);
1521 :
1522 : /* Test invalid control characters. */
1523 0 : for (i = 1; i < 0x20; i++) {
1524 0 : test_path[8] = i;
1525 0 : crtime_matched = smb1_crtime_matches(cli,
1526 : dfs_root_share_name,
1527 : root_crtime,
1528 : test_path);
1529 0 : if (!crtime_matched) {
1530 0 : return false;
1531 : }
1532 : }
1533 :
1534 : /* Test explicit invalid characters. */
1535 0 : for (p = test_str; *p != '\0'; p++) {
1536 0 : test_path[8] = *p;
1537 0 : if (*p == ':') {
1538 : /*
1539 : * Only ':' is treated as an INVALID sharename
1540 : * for a DFS SERVER\\SHARE path.
1541 : */
1542 0 : struct timespec test_crtime = { 0 };
1543 0 : NTSTATUS status = get_smb1_crtime(cli,
1544 : test_path,
1545 : &test_crtime);
1546 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_INVALID)) {
1547 0 : 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 0 : return false;
1554 : }
1555 : } else {
1556 0 : crtime_matched = smb1_crtime_matches(cli,
1557 : dfs_root_share_name,
1558 : root_crtime,
1559 : test_path);
1560 0 : if (!crtime_matched) {
1561 0 : return false;
1562 : }
1563 : }
1564 : }
1565 0 : return true;
1566 : }
1567 :
1568 : /*
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.
1573 : *
1574 : * So here, we're testing the server code, not the client code.
1575 : *
1576 : * Passes cleanly against Windows.
1577 : */
1578 :
1579 2 : bool run_smb1_dfs_paths(int dummy)
1580 : {
1581 2 : struct cli_state *cli = NULL;
1582 0 : NTSTATUS status;
1583 2 : bool dfs_supported = false;
1584 2 : char *dfs_root_share_name = NULL;
1585 2 : struct timespec root_crtime = { 0 };
1586 2 : struct timespec test_crtime = { 0 };
1587 2 : bool crtime_matched = false;
1588 2 : bool retval = false;
1589 2 : bool ok = false;
1590 2 : bool equal = false;
1591 0 : unsigned int i;
1592 2 : uint16_t fnum = (uint16_t)-1;
1593 :
1594 2 : printf("Starting SMB1-DFS-PATHS\n");
1595 :
1596 2 : if (!torture_init_connection(&cli)) {
1597 0 : return false;
1598 : }
1599 :
1600 2 : if (!torture_open_connection(&cli, 0)) {
1601 0 : return false;
1602 : }
1603 :
1604 : /* Ensure this is a DFS share. */
1605 2 : dfs_supported = smbXcli_conn_dfs_supported(cli->conn);
1606 2 : if (!dfs_supported) {
1607 0 : printf("Server %s does not support DFS\n",
1608 0 : smbXcli_conn_remote_name(cli->conn));
1609 0 : return false;
1610 : }
1611 2 : dfs_supported = smbXcli_tcon_is_dfs_share(cli->smb1.tcon);
1612 2 : if (!dfs_supported) {
1613 0 : printf("Share %s does not support DFS\n",
1614 0 : cli->share);
1615 0 : return false;
1616 : }
1617 :
1618 : /* Start with an empty share. */
1619 2 : (void)smb1_dfs_delete(cli, "BAD\\BAD\\BAD");
1620 2 : (void)smb1_dfs_delete(cli, "BAD\\BAD\\file");
1621 2 : (void)smb1_dfs_delete(cli, "BAD\\BAD\\renamed_file");
1622 2 : (void)smb1_dfs_delete(cli, "BAD\\BAD\\hlink");
1623 :
1624 : /*
1625 : * Create the "official" DFS share root name.
1626 : */
1627 2 : dfs_root_share_name = talloc_asprintf(talloc_tos(),
1628 : "\\%s\\%s",
1629 2 : smbXcli_conn_remote_name(cli->conn),
1630 2 : cli->share);
1631 2 : if (dfs_root_share_name == NULL) {
1632 0 : printf("Out of memory\n");
1633 0 : return false;
1634 : }
1635 :
1636 : /* Get the share root crtime. */
1637 2 : status = get_smb1_crtime(cli,
1638 : dfs_root_share_name,
1639 : &root_crtime);
1640 2 : if (!NT_STATUS_IS_OK(status)) {
1641 0 : 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 0 : return false;
1647 : }
1648 :
1649 : /*
1650 : * Test the Windows algorithm for parsing DFS names.
1651 : */
1652 : /*
1653 : * A single "SERVER" element should open and match the share root.
1654 : */
1655 2 : crtime_matched = smb1_crtime_matches(cli,
1656 : dfs_root_share_name,
1657 : root_crtime,
1658 2 : smbXcli_conn_remote_name(cli->conn));
1659 2 : if (!crtime_matched) {
1660 0 : printf("%s:%d Failed to match crtime for %s\n",
1661 : __FILE__,
1662 : __LINE__,
1663 0 : smbXcli_conn_remote_name(cli->conn));
1664 0 : return false;
1665 : }
1666 :
1667 : /* An "" (empty) server name should open and match the share root. */
1668 2 : crtime_matched = smb1_crtime_matches(cli,
1669 : dfs_root_share_name,
1670 : root_crtime,
1671 : "");
1672 2 : if (!crtime_matched) {
1673 0 : printf("%s:%d Failed to match crtime for %s\n",
1674 : __FILE__,
1675 : __LINE__,
1676 : "");
1677 0 : return false;
1678 : }
1679 :
1680 : /*
1681 : * For SMB1 the server just strips off any number of leading '\\'
1682 : * characters. Show this is the case.
1683 : */
1684 22 : for (i = 0; i < 10; i++) {
1685 0 : char leading_backslash_name[20];
1686 20 : leading_backslash_name[i] = '\\';
1687 20 : memcpy(&leading_backslash_name[i+1],
1688 : "SERVER",
1689 : strlen("SERVER")+1);
1690 :
1691 20 : crtime_matched = smb1_crtime_matches(cli,
1692 : dfs_root_share_name,
1693 : root_crtime,
1694 : leading_backslash_name);
1695 20 : if (!crtime_matched) {
1696 0 : printf("%s:%d Failed to match crtime for %s\n",
1697 : __FILE__,
1698 : __LINE__,
1699 : leading_backslash_name);
1700 0 : return false;
1701 : }
1702 : }
1703 :
1704 : /* A "BAD" server name should open and match the share root. */
1705 2 : crtime_matched = smb1_crtime_matches(cli,
1706 : dfs_root_share_name,
1707 : root_crtime,
1708 : "BAD");
1709 2 : if (!crtime_matched) {
1710 0 : printf("%s:%d Failed to match crtime for %s\n",
1711 : __FILE__,
1712 : __LINE__,
1713 : "BAD");
1714 0 : return false;
1715 : }
1716 : /*
1717 : * A "BAD\\BAD" server and share name should open
1718 : * and match the share root.
1719 : */
1720 2 : crtime_matched = smb1_crtime_matches(cli,
1721 : dfs_root_share_name,
1722 : root_crtime,
1723 : "BAD\\BAD");
1724 2 : if (!crtime_matched) {
1725 0 : printf("%s:%d Failed to match crtime for %s\n",
1726 : __FILE__,
1727 : __LINE__,
1728 : "BAD\\BAD");
1729 0 : return false;
1730 : }
1731 : /*
1732 : * Trying to open "BAD\\BAD\\BAD" should get
1733 : * NT_STATUS_OBJECT_NAME_NOT_FOUND.
1734 : */
1735 2 : status = get_smb1_crtime(cli,
1736 : "BAD\\BAD\\BAD",
1737 : &test_crtime);
1738 2 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1739 0 : 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 0 : return false;
1746 : }
1747 : /*
1748 : * Trying to open "BAD\\BAD\\BAD\\BAD" should get
1749 : * NT_STATUS_OBJECT_PATH_NOT_FOUND.
1750 : */
1751 2 : status = get_smb1_crtime(cli,
1752 : "BAD\\BAD\\BAD\\BAD",
1753 : &test_crtime);
1754 2 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
1755 0 : 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 0 : return false;
1762 : }
1763 : /*
1764 : * Test for invalid pathname characters in the servername.
1765 : * They are ignored, and it still opens the share root.
1766 : */
1767 2 : crtime_matched = smb1_crtime_matches(cli,
1768 : dfs_root_share_name,
1769 : root_crtime,
1770 : "::::");
1771 2 : if (!crtime_matched) {
1772 2 : printf("%s:%d Failed to match crtime for %s\n",
1773 : __FILE__,
1774 : __LINE__,
1775 : "::::");
1776 2 : return false;
1777 : }
1778 :
1779 : /*
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.
1784 : */
1785 0 : ok = test_smb1_dfs_sharenames(cli,
1786 : dfs_root_share_name,
1787 : root_crtime);
1788 0 : if (!ok) {
1789 0 : return false;
1790 : }
1791 :
1792 0 : status = smb1cli_ntcreatex(cli->conn,
1793 0 : cli->timeout,
1794 0 : cli->smb1.pid,
1795 0 : cli->smb1.tcon,
1796 0 : 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 0 : if (!NT_STATUS_IS_OK(status)) {
1815 0 : printf("%s:%d smb1cli_ntcreatex on %s returned %s\n",
1816 : __FILE__,
1817 : __LINE__,
1818 : "BAD\\BAD\\file",
1819 : nt_errstr(status));
1820 0 : return false;
1821 : }
1822 :
1823 : /* Close "file" handle. */
1824 0 : (void)smb1cli_close(cli->conn,
1825 0 : cli->timeout,
1826 0 : cli->smb1.pid,
1827 0 : cli->smb1.tcon,
1828 0 : cli->smb1.session,
1829 : fnum,
1830 : 0); /* last_modified */
1831 0 : fnum = (uint16_t)-1;
1832 :
1833 : /*
1834 : * Trying to open "BAD\\BAD\\file" should now get
1835 : * a valid crtime.
1836 : */
1837 0 : status = get_smb1_crtime(cli,
1838 : "BAD\\BAD\\file",
1839 : &test_crtime);
1840 0 : if (!NT_STATUS_IS_OK(status)) {
1841 0 : 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 0 : goto err;
1848 : }
1849 :
1850 : /*
1851 : * This crtime must be different from the root_crtime.
1852 : * This checks we're actually correctly reading crtimes
1853 : * from the filesystem.
1854 : */
1855 0 : equal = (timespec_compare(&test_crtime, &root_crtime) == 0);
1856 0 : if (equal) {
1857 0 : printf("%s:%d Error. crtime of %s must differ from "
1858 : "root_crtime\n",
1859 : __FILE__,
1860 : __LINE__,
1861 : "BAD\\BAD\\file");
1862 0 : goto err;
1863 : }
1864 :
1865 : /*
1866 : * Test different SMB1 renames
1867 : * and hard links.
1868 : */
1869 :
1870 : /* SMBmv only does rename. */
1871 0 : ok = test_smb1_mv(cli,
1872 : "BAD\\BAD\\file");
1873 0 : if (!ok) {
1874 0 : goto err;
1875 : }
1876 :
1877 0 : ok = test_smb1_setpathinfo_rename(cli,
1878 : "BAD\\BAD\\file");
1879 0 : if (!ok) {
1880 0 : goto err;
1881 : }
1882 :
1883 0 : ok = test_smb1_setpathinfo_hardlink(cli,
1884 : "BAD\\BAD\\file");
1885 0 : if (!ok) {
1886 0 : goto err;
1887 : }
1888 :
1889 0 : ok = test_smb1_setfileinfo_rename(cli,
1890 : "BAD\\BAD\\file");
1891 0 : if (!ok) {
1892 0 : goto err;
1893 : }
1894 :
1895 0 : ok = test_smb1_setfileinfo_hardlink(cli,
1896 : "BAD\\BAD\\file");
1897 0 : if (!ok) {
1898 0 : goto err;
1899 : }
1900 :
1901 0 : ok = test_smb1_ntrename_rename(cli,
1902 : "BAD\\BAD\\file");
1903 0 : if (!ok) {
1904 0 : goto err;
1905 : }
1906 :
1907 0 : ok = test_smb1_ntrename_hardlink(cli,
1908 : "BAD\\BAD\\file");
1909 0 : if (!ok) {
1910 0 : goto err;
1911 : }
1912 :
1913 0 : retval = true;
1914 :
1915 0 : err:
1916 :
1917 0 : if (fnum != (uint16_t)-1) {
1918 0 : (void)smb1cli_close(cli->conn,
1919 0 : cli->timeout,
1920 0 : cli->smb1.pid,
1921 0 : cli->smb1.tcon,
1922 0 : cli->smb1.session,
1923 : fnum,
1924 : 0); /* last_modified */
1925 : }
1926 :
1927 : /* Delete anything we made. */
1928 0 : (void)smb1_dfs_delete(cli, "BAD\\BAD\\BAD");
1929 0 : (void)smb1_dfs_delete(cli, "BAD\\BAD\\file");
1930 0 : (void)smb1_dfs_delete(cli, "BAD\\BAD\\renamed_file");
1931 0 : (void)smb1_dfs_delete(cli, "BAD\\BAD\\hlink");
1932 0 : return retval;
1933 : }
1934 :
1935 : /*
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.
1940 : */
1941 :
1942 : /****************************************************************************
1943 : Calculate a safe next_entry_offset.
1944 : ****************************************************************************/
1945 :
1946 30 : static size_t calc_next_entry_offset(const uint8_t *base,
1947 : const uint8_t *pdata_end)
1948 : {
1949 30 : size_t next_entry_offset = (size_t)PULL_LE_U32(base,0);
1950 :
1951 30 : if (next_entry_offset == 0 ||
1952 30 : base + next_entry_offset < base ||
1953 30 : base + next_entry_offset > pdata_end) {
1954 0 : next_entry_offset = pdata_end - base;
1955 : }
1956 30 : return next_entry_offset;
1957 : }
1958 :
1959 30 : 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)
1966 : {
1967 30 : size_t ret = 0;
1968 30 : const uint8_t *base = p;
1969 30 : size_t namelen = 0;
1970 30 : size_t slen = 0;
1971 :
1972 30 : ZERO_STRUCTP(finfo);
1973 :
1974 30 : if (pdata_end - base < 94) {
1975 0 : return pdata_end - base;
1976 : }
1977 30 : p += 4; /* next entry offset */
1978 30 : p += 4; /* fileindex */
1979 : /* Offset zero is "create time", not "change time". */
1980 30 : p += 8;
1981 30 : finfo->atime_ts = interpret_long_date(BVAL(p, 0));
1982 30 : p += 8;
1983 30 : finfo->mtime_ts = interpret_long_date(BVAL(p, 0));
1984 30 : p += 8;
1985 30 : finfo->ctime_ts = interpret_long_date(BVAL(p, 0));
1986 30 : p += 8;
1987 30 : finfo->size = PULL_LE_U64(p, 0);
1988 30 : p += 8;
1989 30 : p += 8; /* alloc size */
1990 30 : finfo->attr = PULL_LE_U32(p, 0);
1991 30 : p += 4;
1992 30 : namelen = PULL_LE_U32(p, 0);
1993 30 : p += 4;
1994 30 : p += 4; /* EA size */
1995 30 : slen = PULL_LE_U8(p, 0);
1996 30 : if (slen > 24) {
1997 : /* Bad short name length. */
1998 0 : return pdata_end - base;
1999 : }
2000 30 : p += 2;
2001 30 : ret = pull_string_talloc(ctx,
2002 : base_ptr,
2003 : recv_flags2,
2004 : &finfo->short_name,
2005 : p,
2006 : slen,
2007 : STR_UNICODE);
2008 30 : if (ret == (size_t)-1) {
2009 0 : return pdata_end - base;
2010 : }
2011 30 : p += 24; /* short name */
2012 30 : if (p + namelen < p || p + namelen > pdata_end) {
2013 0 : return pdata_end - base;
2014 : }
2015 30 : ret = pull_string_talloc(ctx,
2016 : base_ptr,
2017 : recv_flags2,
2018 : &finfo->name,
2019 : p,
2020 : namelen,
2021 : 0);
2022 30 : if (ret == (size_t)-1) {
2023 0 : return pdata_end - base;
2024 : }
2025 30 : return calc_next_entry_offset(base, pdata_end);
2026 : }
2027 :
2028 : /* Single shot SMB1 TRANS2 FindFirst. */
2029 :
2030 10 : 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)
2035 : {
2036 0 : NTSTATUS status;
2037 0 : uint16_t setup[1];
2038 10 : uint8_t *param = NULL;
2039 10 : uint16_t recv_flags2 = 0;
2040 10 : uint8_t *rparam = NULL;
2041 10 : uint32_t num_rparam = 0;
2042 10 : uint8_t *rdata = NULL;
2043 10 : uint32_t num_rdata = 0;
2044 10 : uint16_t num_names_returned = 0;
2045 10 : struct file_info *finfo = NULL;
2046 10 : uint8_t *p2 = NULL;
2047 10 : uint8_t *data_end = NULL;
2048 10 : uint16_t i = 0;
2049 :
2050 10 : PUSH_LE_U16(&setup[0], 0, TRANSACT2_FINDFIRST);
2051 :
2052 10 : param = talloc_array(mem_ctx, uint8_t, 12);
2053 10 : if (param == NULL) {
2054 0 : return NT_STATUS_NO_MEMORY;
2055 : }
2056 :
2057 10 : PUSH_LE_U16(param, 0, FILE_ATTRIBUTE_DIRECTORY |
2058 : FILE_ATTRIBUTE_SYSTEM |
2059 : FILE_ATTRIBUTE_HIDDEN);
2060 10 : PUSH_LE_U16(param, 2, 1366); /* max_matches */
2061 10 : PUSH_LE_U16(param, 4, FLAG_TRANS2_FIND_CLOSE_IF_END);
2062 10 : PUSH_LE_U16(param, 6, SMB_FIND_FILE_BOTH_DIRECTORY_INFO); /* info_level */
2063 :
2064 10 : param = trans2_bytes_push_str(param,
2065 10 : smbXcli_conn_use_unicode(cli->conn),
2066 : search_name,
2067 10 : strlen(search_name)+1,
2068 : NULL);
2069 10 : if (param == NULL) {
2070 0 : return NT_STATUS_NO_MEMORY;
2071 : }
2072 :
2073 : /*
2074 : * A one shot SMB1 findfirst will be enough to
2075 : * return ".", "..", and "file".
2076 : */
2077 10 : 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 10 : talloc_get_size(param), /* num_param */
2089 : 10, /* max returned param */
2090 : NULL, /* data */
2091 : 0, /* num_data */
2092 : SMB_BUFFER_SIZE_MAX, /* max returned 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 10 : if (!NT_STATUS_IS_OK(status)) {
2105 0 : return status;
2106 : }
2107 :
2108 10 : num_names_returned = PULL_LE_U16(rparam, 2);
2109 :
2110 10 : finfo = talloc_array(mem_ctx, struct file_info, num_names_returned);
2111 10 : if (param == NULL) {
2112 0 : return NT_STATUS_NO_MEMORY;
2113 : }
2114 :
2115 10 : p2 = rdata;
2116 10 : data_end = rdata + num_rdata;
2117 :
2118 40 : for (i = 0; i < num_names_returned; i++) {
2119 30 : if (p2 >= data_end) {
2120 0 : break;
2121 : }
2122 30 : if (i == num_names_returned - 1) {
2123 : /* Last entry - fixup the last offset length. */
2124 10 : PUSH_LE_U32(p2, 0, PTR_DIFF((rdata + num_rdata), p2));
2125 : }
2126 :
2127 60 : p2 += get_filename(mem_ctx,
2128 : cli,
2129 : rdata,
2130 : recv_flags2,
2131 : p2,
2132 : data_end,
2133 30 : &finfo[i]);
2134 :
2135 30 : if (finfo->name == NULL) {
2136 0 : 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 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
2143 : }
2144 : }
2145 10 : *num_names = i;
2146 10 : *names = finfo;
2147 10 : return NT_STATUS_OK;
2148 : }
2149 :
2150 : /*
2151 : * Test a specific SMB1 findfirst path to see if it
2152 : * matches a given file array.
2153 : */
2154 8 : 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)
2158 : {
2159 8 : size_t i = 0;
2160 8 : size_t num_finfo = 0;
2161 8 : struct file_info *finfo = NULL;
2162 0 : NTSTATUS status;
2163 :
2164 8 : status = smb1_findfirst(talloc_tos(),
2165 : cli,
2166 : search_path,
2167 : &finfo,
2168 : &num_finfo);
2169 8 : if (!NT_STATUS_IS_OK(status)) {
2170 0 : printf("%s:%d smb1findfirst on %s returned %s\n",
2171 : __FILE__,
2172 : __LINE__,
2173 : search_path,
2174 : nt_errstr(status));
2175 0 : return false;
2176 : }
2177 :
2178 8 : if (num_finfo != num_root_finfo) {
2179 0 : 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 0 : return false;
2186 : }
2187 32 : for (i = 0; i < num_finfo; i++) {
2188 24 : bool match = strequal_m(finfo[i].name,
2189 24 : root_finfo[i].name);
2190 24 : if (!match) {
2191 0 : printf("%s:%d Mismatch. For %s, at position %zu, "
2192 : "finfo[i].name = %s, "
2193 : "root_finfo[i].name = %s\n",
2194 : __FILE__,
2195 : __LINE__,
2196 : search_path,
2197 : i,
2198 0 : finfo[i].name,
2199 0 : root_finfo[i].name);
2200 0 : return false;
2201 : }
2202 : }
2203 8 : TALLOC_FREE(finfo);
2204 8 : return true;
2205 : }
2206 :
2207 : /*
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.
2212 : *
2213 : * So here, we're testing the server code, not the client code.
2214 : *
2215 : * Passes cleanly against Windows.
2216 : */
2217 :
2218 2 : bool run_smb1_dfs_search_paths(int dummy)
2219 : {
2220 2 : struct cli_state *cli = NULL;
2221 0 : NTSTATUS status;
2222 2 : bool dfs_supported = false;
2223 2 : struct file_info *root_finfo = NULL;
2224 2 : size_t num_root_finfo = 0;
2225 2 : bool retval = false;
2226 2 : bool ok = false;
2227 2 : uint16_t fnum = (uint16_t)-1;
2228 :
2229 2 : printf("Starting SMB1-DFS-SEARCH-PATHS\n");
2230 :
2231 2 : if (!torture_init_connection(&cli)) {
2232 0 : return false;
2233 : }
2234 :
2235 2 : if (!torture_open_connection(&cli, 0)) {
2236 0 : return false;
2237 : }
2238 :
2239 : /* Ensure this is a DFS share. */
2240 2 : dfs_supported = smbXcli_conn_dfs_supported(cli->conn);
2241 2 : if (!dfs_supported) {
2242 0 : printf("Server %s does not support DFS\n",
2243 0 : smbXcli_conn_remote_name(cli->conn));
2244 0 : return false;
2245 : }
2246 2 : dfs_supported = smbXcli_tcon_is_dfs_share(cli->smb1.tcon);
2247 2 : if (!dfs_supported) {
2248 0 : printf("Share %s does not support DFS\n",
2249 0 : cli->share);
2250 0 : return false;
2251 : }
2252 :
2253 : /* Start clean. */
2254 2 : (void)smb1_dfs_delete(cli, "BAD\\BAD\\file");
2255 :
2256 : /* Create a test file to search for. */
2257 2 : status = smb1cli_ntcreatex(cli->conn,
2258 2 : cli->timeout,
2259 2 : cli->smb1.pid,
2260 2 : cli->smb1.tcon,
2261 2 : 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 2 : if (!NT_STATUS_IS_OK(status)) {
2280 0 : printf("%s:%d smb1cli_ntcreatex on %s returned %s\n",
2281 : __FILE__,
2282 : __LINE__,
2283 : "BAD\\BAD\\file",
2284 : nt_errstr(status));
2285 0 : return false;
2286 : }
2287 :
2288 : /* Close "file" handle. */
2289 2 : (void)smb1cli_close(cli->conn,
2290 2 : cli->timeout,
2291 2 : cli->smb1.pid,
2292 2 : cli->smb1.tcon,
2293 2 : cli->smb1.session,
2294 : fnum,
2295 : 0); /* last_modified */
2296 2 : fnum = (uint16_t)-1;
2297 :
2298 : /* Get the list of files in the share. */
2299 2 : status = smb1_findfirst(talloc_tos(),
2300 : cli,
2301 : "SERVER\\SHARE\\*",
2302 : &root_finfo,
2303 : &num_root_finfo);
2304 2 : if (!NT_STATUS_IS_OK(status)) {
2305 0 : printf("%s:%d smb1findfirst on %s returned %s\n",
2306 : __FILE__,
2307 : __LINE__,
2308 : "SERVER\\SHARE\\*",
2309 : nt_errstr(status));
2310 0 : return false;
2311 : }
2312 :
2313 : /*
2314 : * Try different search names. They should
2315 : * all match the root directory list.
2316 : */
2317 2 : ok = test_smb1_findfirst_path(cli,
2318 : "\\SERVER\\SHARE\\*",
2319 : root_finfo,
2320 : num_root_finfo);
2321 2 : if (!ok) {
2322 0 : goto err;
2323 : }
2324 :
2325 2 : ok = test_smb1_findfirst_path(cli,
2326 : "*",
2327 : root_finfo,
2328 : num_root_finfo);
2329 2 : if (!ok) {
2330 0 : goto err;
2331 : }
2332 2 : ok = test_smb1_findfirst_path(cli,
2333 : "\\*",
2334 : root_finfo,
2335 : num_root_finfo);
2336 2 : if (!ok) {
2337 0 : goto err;
2338 : }
2339 2 : ok = test_smb1_findfirst_path(cli,
2340 : "\\SERVER\\*",
2341 : root_finfo,
2342 : num_root_finfo);
2343 2 : if (!ok) {
2344 0 : goto err;
2345 : }
2346 2 : retval = true;
2347 :
2348 2 : err:
2349 :
2350 2 : if (fnum != (uint16_t)-1) {
2351 0 : (void)smb1cli_close(cli->conn,
2352 0 : cli->timeout,
2353 0 : cli->smb1.pid,
2354 0 : cli->smb1.tcon,
2355 0 : cli->smb1.session,
2356 : fnum,
2357 : 0); /* last_modified */
2358 : }
2359 :
2360 : /* Delete anything we made. */
2361 2 : (void)smb1_dfs_delete(cli, "BAD\\BAD\\file");
2362 2 : return retval;
2363 : }
2364 :
2365 4 : static bool smb1_create_testfile(struct cli_state *cli,
2366 : const char *path)
2367 : {
2368 0 : NTSTATUS status;
2369 4 : uint16_t fnum = (uint16_t)-1;
2370 :
2371 : /* Create a test file. */
2372 4 : status = smb1cli_ntcreatex(cli->conn,
2373 4 : 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 4 : if (!NT_STATUS_IS_OK(status)) {
2395 0 : printf("%s:%d smb1cli_ntcreatex on %s returned %s\n",
2396 : __FILE__,
2397 : __LINE__,
2398 : path,
2399 : nt_errstr(status));
2400 0 : return false;
2401 : }
2402 :
2403 : /* Close "file" handle. */
2404 4 : (void)smb1cli_close(cli->conn,
2405 4 : cli->timeout,
2406 : cli->smb1.pid,
2407 : cli->smb1.tcon,
2408 : cli->smb1.session,
2409 : fnum,
2410 : 0); /* last_modified */
2411 4 : return true;
2412 : }
2413 :
2414 6 : static NTSTATUS smb1_unlink(struct cli_state *cli,
2415 : const char *path)
2416 : {
2417 0 : uint16_t vwv[1];
2418 6 : uint8_t *bytes = NULL;
2419 :
2420 6 : PUSH_LE_U16(vwv, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2421 6 : bytes = talloc_array(talloc_tos(), uint8_t, 1);
2422 6 : if (bytes == NULL) {
2423 0 : return NT_STATUS_NO_MEMORY;
2424 : }
2425 6 : bytes[0] = 4;
2426 6 : bytes = smb_bytes_push_str(bytes,
2427 6 : smbXcli_conn_use_unicode(cli->conn),
2428 : path,
2429 6 : strlen(path)+1,
2430 : NULL);
2431 6 : if (bytes == NULL) {
2432 0 : return NT_STATUS_NO_MEMORY;
2433 : }
2434 :
2435 6 : return cli_smb(talloc_tos(),
2436 : cli,
2437 : SMBunlink, /* command. */
2438 : 0, /* additional_flags. */
2439 : 1, /* wct. */
2440 : vwv, /* vwv. */
2441 6 : 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. */
2449 : }
2450 :
2451 2 : static bool test_smb1_unlink(struct cli_state *cli)
2452 : {
2453 0 : NTSTATUS status;
2454 2 : bool retval = false;
2455 2 : bool ok = false;
2456 :
2457 : /* Start clean. */
2458 2 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\file");
2459 :
2460 : /* Create a test file. */
2461 2 : ok = smb1_create_testfile(cli, "\\BAD\\BAD\\file");
2462 2 : if (!ok) {
2463 0 : printf("%s:%d failed to create test file %s\n",
2464 : __FILE__,
2465 : __LINE__,
2466 : "\\BAD\\BAD\\file");
2467 0 : goto err;
2468 : }
2469 :
2470 2 : status = smb1_unlink(cli, "file");
2471 2 : if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
2472 0 : 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 0 : goto err;
2479 : }
2480 2 : status = smb1_unlink(cli, "\\BAD\\file");
2481 2 : if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
2482 0 : 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 0 : goto err;
2489 : }
2490 2 : status = smb1_unlink(cli, "\\BAD\\BAD\\file");
2491 2 : if (!NT_STATUS_IS_OK(status)) {
2492 0 : printf("%s:%d SMB1unlink on %s returned %s\n",
2493 : __FILE__,
2494 : __LINE__,
2495 : "\\BAD\\BAD\\file",
2496 : nt_errstr(status));
2497 0 : goto err;
2498 : }
2499 :
2500 2 : retval = true;
2501 :
2502 2 : err:
2503 :
2504 2 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\file");
2505 2 : return retval;
2506 : }
2507 :
2508 8 : static NTSTATUS smb1_mkdir(struct cli_state *cli,
2509 : const char *path)
2510 : {
2511 8 : uint8_t *bytes = NULL;
2512 :
2513 8 : bytes = talloc_array(talloc_tos(), uint8_t, 1);
2514 8 : if (bytes == NULL) {
2515 0 : return NT_STATUS_NO_MEMORY;
2516 : }
2517 8 : bytes[0] = 4;
2518 8 : bytes = smb_bytes_push_str(bytes,
2519 8 : smbXcli_conn_use_unicode(cli->conn),
2520 : path,
2521 8 : strlen(path)+1,
2522 : NULL);
2523 8 : if (bytes == NULL) {
2524 0 : return NT_STATUS_NO_MEMORY;
2525 : }
2526 :
2527 8 : return cli_smb(talloc_tos(),
2528 : cli,
2529 : SMBmkdir, /* command. */
2530 : 0, /* additional_flags. */
2531 : 0, /* wct. */
2532 : NULL, /* vwv. */
2533 8 : 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. */
2541 : }
2542 :
2543 2 : static bool test_smb1_mkdir(struct cli_state *cli)
2544 : {
2545 0 : NTSTATUS status;
2546 2 : bool retval = false;
2547 :
2548 : /* Start clean. */
2549 2 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\dir");
2550 :
2551 2 : status = smb1_mkdir(cli, "dir");
2552 2 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2553 0 : 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 0 : goto err;
2560 : }
2561 2 : status = smb1_mkdir(cli, "\\BAD\\dir");
2562 2 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2563 0 : 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 0 : goto err;
2570 : }
2571 2 : status = smb1_mkdir(cli, "\\BAD\\BAD\\dir");
2572 2 : if (!NT_STATUS_IS_OK(status)) {
2573 0 : printf("%s:%d SMB1mkdir on %s returned %s\n",
2574 : __FILE__,
2575 : __LINE__,
2576 : "\\BAD\\BAD\\dir",
2577 : nt_errstr(status));
2578 0 : goto err;
2579 : }
2580 :
2581 2 : retval = true;
2582 :
2583 2 : err:
2584 :
2585 2 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\dir");
2586 2 : return retval;
2587 : }
2588 :
2589 6 : static NTSTATUS smb1_rmdir(struct cli_state *cli,
2590 : const char *path)
2591 : {
2592 6 : uint8_t *bytes = NULL;
2593 :
2594 6 : bytes = talloc_array(talloc_tos(), uint8_t, 1);
2595 6 : if (bytes == NULL) {
2596 0 : return NT_STATUS_NO_MEMORY;
2597 : }
2598 6 : bytes[0] = 4;
2599 6 : bytes = smb_bytes_push_str(bytes,
2600 6 : smbXcli_conn_use_unicode(cli->conn),
2601 : path,
2602 6 : strlen(path)+1,
2603 : NULL);
2604 6 : if (bytes == NULL) {
2605 0 : return NT_STATUS_NO_MEMORY;
2606 : }
2607 :
2608 6 : return cli_smb(talloc_tos(),
2609 : cli,
2610 : SMBrmdir, /* command. */
2611 : 0, /* additional_flags. */
2612 : 0, /* wct. */
2613 : NULL, /* vwv. */
2614 6 : 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. */
2622 : }
2623 :
2624 2 : static bool test_smb1_rmdir(struct cli_state *cli)
2625 : {
2626 0 : NTSTATUS status;
2627 2 : bool retval = false;
2628 :
2629 : /* Start clean. */
2630 2 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\dir");
2631 :
2632 2 : status = smb1_mkdir(cli, "\\BAD\\BAD\\dir");
2633 2 : if (!NT_STATUS_IS_OK(status)) {
2634 0 : printf("%s:%d SMB1rmdir on %s returned %s\n",
2635 : __FILE__,
2636 : __LINE__,
2637 : "\\BAD\\BAD\\dir",
2638 : nt_errstr(status));
2639 0 : goto err;
2640 : }
2641 :
2642 2 : status = smb1_rmdir(cli, "dir");
2643 2 : if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
2644 0 : 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 0 : goto err;
2651 : }
2652 2 : status = smb1_rmdir(cli, "\\BAD\\dir");
2653 2 : if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
2654 0 : 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 0 : goto err;
2661 : }
2662 2 : status = smb1_rmdir(cli, "\\BAD\\BAD\\dir");
2663 2 : if (!NT_STATUS_IS_OK(status)) {
2664 0 : printf("%s:%d SMB1rmdir on %s returned %s\n",
2665 : __FILE__,
2666 : __LINE__,
2667 : "\\BAD\\BAD\\dir",
2668 : nt_errstr(status));
2669 0 : goto err;
2670 : }
2671 :
2672 2 : retval = true;
2673 :
2674 2 : err:
2675 :
2676 2 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\dir");
2677 2 : return retval;
2678 : }
2679 :
2680 6 : static NTSTATUS smb1_ntcreatex(struct cli_state *cli,
2681 : const char *path)
2682 : {
2683 0 : NTSTATUS status;
2684 6 : uint16_t fnum = (uint16_t)-1;
2685 :
2686 6 : status = smb1cli_ntcreatex(cli->conn,
2687 6 : 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 6 : if (!NT_STATUS_IS_OK(status)) {
2709 4 : return status;
2710 : }
2711 :
2712 : /* Close "file" handle. */
2713 2 : (void)smb1cli_close(cli->conn,
2714 2 : cli->timeout,
2715 : cli->smb1.pid,
2716 : cli->smb1.tcon,
2717 : cli->smb1.session,
2718 : fnum,
2719 : 0); /* last_modified */
2720 2 : return NT_STATUS_OK;
2721 : }
2722 :
2723 2 : static bool test_smb1_ntcreatex(struct cli_state *cli)
2724 : {
2725 0 : NTSTATUS status;
2726 2 : bool retval = false;
2727 :
2728 : /* Start clean. */
2729 2 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\ntcreateXfile");
2730 :
2731 2 : status = smb1_ntcreatex(cli, "ntcreateXfile");
2732 2 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2733 0 : 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 0 : goto err;
2740 : }
2741 2 : status = smb1_ntcreatex(cli, "\\BAD\\ntcreateXfile");
2742 2 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2743 0 : 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 0 : goto err;
2750 : }
2751 2 : status = smb1_ntcreatex(cli, "\\BAD\\BAD\\ntcreateXfile");
2752 2 : if (!NT_STATUS_IS_OK(status)) {
2753 0 : printf("%s:%d SMB1ntcreateX on %s returned %s\n",
2754 : __FILE__,
2755 : __LINE__,
2756 : "\\BAD\\BAD\\ntcreateXfile",
2757 : nt_errstr(status));
2758 0 : goto err;
2759 : }
2760 :
2761 2 : retval = true;
2762 :
2763 2 : err:
2764 :
2765 2 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\ntcreateXfile");
2766 2 : return retval;
2767 : }
2768 :
2769 6 : static NTSTATUS smb1_nttrans_create(struct cli_state *cli,
2770 : const char *path)
2771 : {
2772 6 : uint8_t *param = NULL;
2773 6 : size_t converted_len = 0;
2774 6 : uint8_t *rparam = NULL;
2775 6 : uint32_t num_rparam = 0;
2776 6 : uint16_t fnum = (uint16_t)-1;
2777 0 : NTSTATUS status;
2778 :
2779 6 : param = talloc_zero_array(talloc_tos(), uint8_t, 53);
2780 6 : if (param == NULL) {
2781 0 : return NT_STATUS_NO_MEMORY;
2782 : }
2783 :
2784 6 : param = trans2_bytes_push_str(param,
2785 6 : smbXcli_conn_use_unicode(cli->conn),
2786 : path,
2787 : strlen(path),
2788 : &converted_len);
2789 6 : if (param == NULL) {
2790 0 : return NT_STATUS_NO_MEMORY;
2791 : }
2792 :
2793 6 : PUSH_LE_U32(param, 8, SEC_STD_SYNCHRONIZE|
2794 : SEC_STD_DELETE |
2795 : SEC_FILE_READ_DATA|
2796 : SEC_FILE_READ_ATTRIBUTE); /* DesiredAccess */
2797 6 : PUSH_LE_U32(param, 20, FILE_ATTRIBUTE_NORMAL);
2798 6 : PUSH_LE_U32(param, 24, FILE_SHARE_READ|
2799 : FILE_SHARE_WRITE|
2800 : FILE_SHARE_DELETE); /* ShareAccess */
2801 6 : PUSH_LE_U32(param, 28, FILE_CREATE);
2802 6 : PUSH_LE_U32(param, 44, converted_len);
2803 6 : PUSH_LE_U32(param, 48, 0x02); /* ImpersonationLevel */
2804 :
2805 6 : 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 6 : 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 6 : if (!NT_STATUS_IS_OK(status)) {
2832 4 : return status;
2833 : }
2834 2 : fnum = PULL_LE_U16(param, 2);
2835 : /* Close "file" handle. */
2836 2 : (void)smb1cli_close(cli->conn,
2837 2 : cli->timeout,
2838 : cli->smb1.pid,
2839 : cli->smb1.tcon,
2840 : cli->smb1.session,
2841 : fnum,
2842 : 0); /* last_modified */
2843 2 : return NT_STATUS_OK;
2844 : }
2845 :
2846 2 : static bool test_smb1_nttrans_create(struct cli_state *cli)
2847 : {
2848 0 : NTSTATUS status;
2849 2 : bool retval = false;
2850 :
2851 : /* Start clean. */
2852 2 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\nttransfile");
2853 :
2854 2 : status = smb1_nttrans_create(cli, "nttransfile");
2855 2 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2856 0 : 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 0 : goto err;
2863 : }
2864 2 : status = smb1_nttrans_create(cli, "\\BAD\\nttransfile");
2865 2 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2866 0 : 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 0 : goto err;
2873 : }
2874 2 : status = smb1_nttrans_create(cli, "\\BAD\\BAD\\nttransfile");
2875 2 : if (!NT_STATUS_IS_OK(status)) {
2876 0 : 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 0 : goto err;
2882 : }
2883 :
2884 2 : retval = true;
2885 :
2886 2 : err:
2887 :
2888 2 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\nttransfile");
2889 2 : return retval;
2890 : }
2891 :
2892 : struct smb1_openx_state {
2893 : const char *fname;
2894 : uint16_t vwv[15];
2895 : uint16_t fnum;
2896 : struct iovec bytes;
2897 : };
2898 :
2899 : static void smb1_openx_done(struct tevent_req *subreq);
2900 :
2901 6 : 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)
2905 : {
2906 6 : struct tevent_req *req = NULL;
2907 6 : struct tevent_req *subreq = NULL;
2908 6 : uint16_t accessmode = 0;
2909 6 : struct smb1_openx_state *state = NULL;
2910 6 : uint8_t *bytes = NULL;
2911 0 : NTSTATUS status;
2912 :
2913 6 : req = tevent_req_create(mem_ctx, &state, struct smb1_openx_state);
2914 6 : if (req == NULL) {
2915 0 : return NULL;
2916 : }
2917 :
2918 6 : accessmode = (DENY_NONE<<4);
2919 6 : accessmode |= DOS_OPEN_RDONLY;
2920 :
2921 6 : PUSH_LE_U8(state->vwv + 0, 0, 0xFF);
2922 6 : PUSH_LE_U16(state->vwv + 3, 0, accessmode);
2923 6 : PUSH_LE_U16(state->vwv + 4, 0,
2924 : FILE_ATTRIBUTE_SYSTEM |
2925 : FILE_ATTRIBUTE_HIDDEN |
2926 : FILE_ATTRIBUTE_DIRECTORY);
2927 6 : PUSH_LE_U16(state->vwv + 8,
2928 : 0,
2929 : OPENX_FILE_CREATE_IF_NOT_EXIST| OPENX_FILE_EXISTS_FAIL);
2930 :
2931 6 : bytes = talloc_array(state, uint8_t, 0);
2932 6 : if (tevent_req_nomem(bytes, req)) {
2933 0 : return tevent_req_post(req, ev);
2934 : }
2935 6 : bytes = smb_bytes_push_str(bytes,
2936 6 : smbXcli_conn_use_unicode(cli->conn),
2937 : path,
2938 6 : strlen(path)+1,
2939 : NULL);
2940 6 : if (tevent_req_nomem(bytes, req)) {
2941 0 : return tevent_req_post(req, ev);
2942 : }
2943 :
2944 6 : state->bytes.iov_base = (void *)bytes;
2945 6 : state->bytes.iov_len = talloc_get_size(bytes);
2946 12 : subreq = cli_smb_req_create(state,
2947 : ev,
2948 : cli,
2949 : SMBopenX, /* cmd */
2950 : 0, /* additional_flags */
2951 : 0, /* additional_flags2 */
2952 : 15, /* num_vwv */
2953 6 : state->vwv, /* vwv */
2954 : 1, /* iovcount */
2955 6 : &state->bytes); /* iovec */
2956 6 : if (tevent_req_nomem(subreq, req)) {
2957 0 : return tevent_req_post(req, ev);
2958 : }
2959 6 : tevent_req_set_callback(subreq, smb1_openx_done, req);
2960 :
2961 6 : status = smb1cli_req_chain_submit(&subreq, 1);
2962 6 : if (tevent_req_nterror(req, status)) {
2963 0 : return tevent_req_post(req, ev);
2964 : }
2965 6 : return req;
2966 : }
2967 :
2968 6 : static void smb1_openx_done(struct tevent_req *subreq)
2969 : {
2970 6 : struct tevent_req *req = tevent_req_callback_data(
2971 : subreq, struct tevent_req);
2972 6 : struct smb1_openx_state *state = tevent_req_data(
2973 : req, struct smb1_openx_state);
2974 6 : uint8_t wct = 0;
2975 6 : uint16_t *vwv = NULL;
2976 0 : NTSTATUS status;
2977 :
2978 6 : 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 6 : TALLOC_FREE(subreq);
2987 6 : if (tevent_req_nterror(req, status)) {
2988 4 : return;
2989 : }
2990 2 : state->fnum = PULL_LE_U16(vwv+2, 0);
2991 2 : tevent_req_done(req);
2992 : }
2993 :
2994 6 : static NTSTATUS smb1_openx_recv(struct tevent_req *req, uint16_t *pfnum)
2995 : {
2996 6 : struct smb1_openx_state *state = tevent_req_data(
2997 : req, struct smb1_openx_state);
2998 0 : NTSTATUS status;
2999 :
3000 6 : if (tevent_req_is_nterror(req, &status)) {
3001 4 : return status;
3002 : }
3003 2 : *pfnum = state->fnum;
3004 2 : return NT_STATUS_OK;
3005 : }
3006 :
3007 6 : static NTSTATUS smb1_openx(struct cli_state *cli, const char *path)
3008 : {
3009 6 : TALLOC_CTX *frame = talloc_stackframe();
3010 6 : struct tevent_context *ev = NULL;
3011 6 : struct tevent_req *req = NULL;
3012 6 : uint16_t fnum = (uint16_t)-1;
3013 6 : NTSTATUS status = NT_STATUS_NO_MEMORY;
3014 :
3015 6 : ev = samba_tevent_context_init(frame);
3016 6 : if (ev == NULL) {
3017 0 : goto fail;
3018 : }
3019 :
3020 6 : req = smb1_openx_send(frame,
3021 : ev,
3022 : cli,
3023 : path);
3024 6 : if (req == NULL) {
3025 0 : goto fail;
3026 : }
3027 :
3028 6 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3029 0 : goto fail;
3030 : }
3031 :
3032 6 : status = smb1_openx_recv(req, &fnum);
3033 6 : fail:
3034 :
3035 : /* Close "file" handle. */
3036 6 : if (fnum != (uint16_t)-1) {
3037 2 : (void)smb1cli_close(cli->conn,
3038 2 : cli->timeout,
3039 : cli->smb1.pid,
3040 : cli->smb1.tcon,
3041 : cli->smb1.session,
3042 : fnum,
3043 : 0); /* last_modified */
3044 : }
3045 6 : TALLOC_FREE(frame);
3046 6 : return status;
3047 : }
3048 :
3049 2 : static bool test_smb1_openx(struct cli_state *cli)
3050 : {
3051 0 : NTSTATUS status;
3052 2 : bool retval = false;
3053 :
3054 : /* Start clean. */
3055 2 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\openxfile");
3056 :
3057 2 : status = smb1_openx(cli, "openxfile");
3058 2 : if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
3059 0 : 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 0 : goto err;
3066 : }
3067 2 : status = smb1_openx(cli, "\\BAD\\openxfile");
3068 2 : if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
3069 0 : 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 0 : goto err;
3076 : }
3077 2 : status = smb1_openx(cli, "\\BAD\\BAD\\openxfile");
3078 2 : if (!NT_STATUS_IS_OK(status)) {
3079 0 : printf("%s:%d SMB1openx on %s returned %s\n",
3080 : __FILE__,
3081 : __LINE__,
3082 : "\\BAD\\BAD\\openxfile",
3083 : nt_errstr(status));
3084 0 : goto err;
3085 : }
3086 :
3087 2 : retval = true;
3088 :
3089 2 : err:
3090 :
3091 2 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\openxfile");
3092 2 : return retval;
3093 : }
3094 :
3095 6 : static NTSTATUS smb1_open(struct cli_state *cli,
3096 : const char *path,
3097 : uint16_t *pfnum)
3098 : {
3099 6 : uint16_t vwv[2] = { 0, 0};
3100 6 : uint8_t *bytes = NULL;
3101 6 : uint16_t accessmode = 0;
3102 6 : uint16_t *return_words = NULL;
3103 6 : uint8_t return_wcount = 0;
3104 0 : NTSTATUS status;
3105 :
3106 6 : accessmode = (DENY_NONE<<4);
3107 6 : accessmode |= DOS_OPEN_RDONLY;
3108 :
3109 6 : PUSH_LE_U16(vwv + 0, 0, accessmode);
3110 6 : PUSH_LE_U16(vwv + 1, 0, FILE_ATTRIBUTE_NORMAL);
3111 :
3112 6 : bytes = talloc_array(talloc_tos(), uint8_t, 1);
3113 6 : if (bytes == NULL) {
3114 0 : return NT_STATUS_NO_MEMORY;
3115 : }
3116 6 : bytes[0] = 4;
3117 6 : bytes = smb_bytes_push_str(bytes,
3118 6 : smbXcli_conn_use_unicode(cli->conn),
3119 : path,
3120 6 : strlen(path)+1,
3121 : NULL);
3122 6 : if (bytes == NULL) {
3123 0 : return NT_STATUS_NO_MEMORY;
3124 : }
3125 :
3126 6 : status = cli_smb(talloc_tos(),
3127 : cli,
3128 : SMBopen, /* command. */
3129 : 0, /* additional_flags. */
3130 : 2, /* wct. */
3131 : vwv, /* vwv. */
3132 6 : 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 6 : if (!NT_STATUS_IS_OK(status)) {
3141 4 : return status;
3142 : }
3143 2 : *pfnum = PULL_LE_U16(return_words, 0);
3144 2 : return status;
3145 : }
3146 :
3147 2 : static bool test_smb1_open(struct cli_state *cli)
3148 : {
3149 0 : NTSTATUS status;
3150 2 : bool retval = false;
3151 2 : bool ok = false;
3152 2 : bool equal = false;
3153 2 : uint16_t fnum = (uint16_t)-1;
3154 2 : struct timespec testfile_crtime = { 0 };
3155 2 : struct timespec open_crtime = { 0 };
3156 :
3157 : /* Start clean. */
3158 2 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\openfile");
3159 :
3160 : /* Create a test file. */
3161 2 : ok = smb1_create_testfile(cli, "\\BAD\\BAD\\openfile");
3162 2 : if (!ok) {
3163 0 : printf("%s:%d failed to create test file %s\n",
3164 : __FILE__,
3165 : __LINE__,
3166 : "\\BAD\\BAD\\openfile");
3167 0 : goto err;
3168 : }
3169 :
3170 : /* Get the test file crtime number. */
3171 2 : status = get_smb1_crtime(cli,
3172 : "\\BAD\\BAD\\openfile",
3173 : &testfile_crtime);
3174 2 : if (!NT_STATUS_IS_OK(status)) {
3175 0 : printf("%s:%d Failed to get crtime for %s, (%s)\n",
3176 : __FILE__,
3177 : __LINE__,
3178 : "\\BAD\\BAD\\openfile",
3179 : nt_errstr(status));
3180 0 : goto err;
3181 : }
3182 :
3183 2 : status = smb1_open(cli, "openfile", &fnum);
3184 2 : if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
3185 0 : 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 0 : goto err;
3192 : }
3193 2 : status = smb1_open(cli, "\\BAD\\openfile", &fnum);
3194 2 : if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
3195 0 : 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 0 : goto err;
3202 : }
3203 2 : status = smb1_open(cli, "\\BAD\\BAD\\openfile", &fnum);
3204 2 : if (!NT_STATUS_IS_OK(status)) {
3205 0 : printf("%s:%d failed to open test file %s (%s)\n",
3206 : __FILE__,
3207 : __LINE__,
3208 : "\\BAD\\BAD\\openfile",
3209 : nt_errstr(status));
3210 0 : goto err;
3211 : }
3212 :
3213 2 : 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 2 : if (!NT_STATUS_IS_OK(status)) {
3223 0 : 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 0 : goto err;
3229 : }
3230 2 : equal = (timespec_compare(&testfile_crtime, &open_crtime) == 0);
3231 2 : if (!equal) {
3232 0 : printf("%s:%d crtime mismatch of test file %s\n",
3233 : __FILE__,
3234 : __LINE__,
3235 : "\\BAD\\BAD\\openfile");
3236 0 : goto err;
3237 : }
3238 :
3239 2 : retval = true;
3240 :
3241 2 : err:
3242 :
3243 : /* Close "openfile" handle. */
3244 2 : if (fnum != (uint16_t)-1) {
3245 2 : (void)smb1cli_close(cli->conn,
3246 2 : cli->timeout,
3247 : cli->smb1.pid,
3248 : cli->smb1.tcon,
3249 : cli->smb1.session,
3250 : fnum,
3251 : 0); /* last_modified */
3252 : }
3253 2 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\openfile");
3254 2 : return retval;
3255 : }
3256 :
3257 2 : static NTSTATUS smb1_create(struct cli_state *cli,
3258 : const char *path,
3259 : uint16_t smb1_operation,
3260 : uint16_t *pfnum)
3261 : {
3262 2 : uint16_t vwv[3] = { 0, 0, 0};
3263 2 : uint8_t *bytes = NULL;
3264 2 : uint16_t *return_words = NULL;
3265 2 : uint8_t return_wcount = 0;
3266 0 : NTSTATUS status;
3267 :
3268 2 : PUSH_LE_U16(vwv + 0, 0, FILE_ATTRIBUTE_NORMAL);
3269 :
3270 2 : bytes = talloc_array(talloc_tos(), uint8_t, 1);
3271 2 : if (bytes == NULL) {
3272 0 : return NT_STATUS_NO_MEMORY;
3273 : }
3274 2 : bytes[0] = 4;
3275 2 : bytes = smb_bytes_push_str(bytes,
3276 2 : smbXcli_conn_use_unicode(cli->conn),
3277 : path,
3278 2 : strlen(path)+1,
3279 : NULL);
3280 2 : if (bytes == NULL) {
3281 0 : return NT_STATUS_NO_MEMORY;
3282 : }
3283 :
3284 2 : status = cli_smb(talloc_tos(),
3285 : cli,
3286 : smb1_operation, /* command. */
3287 : 0, /* additional_flags. */
3288 : 3, /* wct. */
3289 : vwv, /* vwv. */
3290 2 : talloc_get_size(bytes), /* num_bytes. */
3291 : bytes, /* bytes. */
3292 : NULL, /* result parent. */
3293 : 1, /* min_wct. */
3294 : &return_wcount, /* return wcount. */
3295 : &return_words, /* return wvw. */
3296 : NULL, /* return byte count. */
3297 : NULL); /* return bytes. */
3298 2 : if (!NT_STATUS_IS_OK(status)) {
3299 2 : return status;
3300 : }
3301 0 : *pfnum = PULL_LE_U16(return_words, 0);
3302 0 : return status;
3303 : }
3304 :
3305 2 : static bool test_smb1_create(struct cli_state *cli)
3306 : {
3307 0 : NTSTATUS status;
3308 2 : bool retval = false;
3309 2 : uint16_t fnum = (uint16_t)-1;
3310 :
3311 : /* Start clean. */
3312 2 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\createfile");
3313 2 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\mknewfile");
3314 :
3315 2 : status = smb1_create(cli, "createfile", SMBcreate, &fnum);
3316 2 : if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
3317 2 : printf("%s:%d SMB1create of %s should get "
3318 : "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3319 : __FILE__,
3320 : __LINE__,
3321 : "createfile",
3322 : nt_errstr(status));
3323 2 : goto err;
3324 : }
3325 0 : status = smb1_create(cli, "\\BAD\\createfile", SMBcreate, &fnum);
3326 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
3327 0 : printf("%s:%d SMB1open of %s should get "
3328 : "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3329 : __FILE__,
3330 : __LINE__,
3331 : "\\BAD\\openfile",
3332 : nt_errstr(status));
3333 0 : goto err;
3334 : }
3335 0 : status = smb1_create(cli, "\\BAD\\BAD\\createfile", SMBcreate, &fnum);
3336 0 : if (!NT_STATUS_IS_OK(status)) {
3337 0 : printf("%s:%d failed to create file %s (%s)\n",
3338 : __FILE__,
3339 : __LINE__,
3340 : "\\BAD\\BAD\\createfile",
3341 : nt_errstr(status));
3342 0 : goto err;
3343 : }
3344 :
3345 0 : (void)smb1cli_close(cli->conn,
3346 0 : cli->timeout,
3347 : cli->smb1.pid,
3348 : cli->smb1.tcon,
3349 : cli->smb1.session,
3350 : fnum,
3351 : 0); /* last_modified */
3352 :
3353 0 : fnum = (uint16_t)-1;
3354 :
3355 : /* Now do the same with SMBmknew */
3356 0 : status = smb1_create(cli, "mknewfile", SMBmknew, &fnum);
3357 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
3358 0 : printf("%s:%d SMB1mknew of %s should get "
3359 : "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3360 : __FILE__,
3361 : __LINE__,
3362 : "mknewfile",
3363 : nt_errstr(status));
3364 0 : goto err;
3365 : }
3366 0 : status = smb1_create(cli, "\\BAD\\mknewfile", SMBmknew, &fnum);
3367 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
3368 0 : printf("%s:%d SMB1mknew of %s should get "
3369 : "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3370 : __FILE__,
3371 : __LINE__,
3372 : "\\BAD\\mknewfile",
3373 : nt_errstr(status));
3374 0 : goto err;
3375 : }
3376 0 : status = smb1_create(cli, "\\BAD\\BAD\\mknewfile", SMBmknew, &fnum);
3377 0 : if (!NT_STATUS_IS_OK(status)) {
3378 0 : printf("%s:%d failed to create file %s (%s)\n",
3379 : __FILE__,
3380 : __LINE__,
3381 : "\\BAD\\BAD\\mknewfile",
3382 : nt_errstr(status));
3383 0 : goto err;
3384 : }
3385 :
3386 0 : (void)smb1cli_close(cli->conn,
3387 0 : cli->timeout,
3388 : cli->smb1.pid,
3389 : cli->smb1.tcon,
3390 : cli->smb1.session,
3391 : fnum,
3392 : 0); /* last_modified */
3393 :
3394 0 : fnum = (uint16_t)-1;
3395 :
3396 0 : retval = true;
3397 :
3398 2 : err:
3399 :
3400 : /* Close "openfile" handle. */
3401 2 : if (fnum != (uint16_t)-1) {
3402 0 : (void)smb1cli_close(cli->conn,
3403 0 : cli->timeout,
3404 : cli->smb1.pid,
3405 : cli->smb1.tcon,
3406 : cli->smb1.session,
3407 : fnum,
3408 : 0); /* last_modified */
3409 : }
3410 2 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\createfile");
3411 2 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\mknewfile");
3412 2 : return retval;
3413 : }
3414 :
3415 0 : static NTSTATUS smb1_getatr(struct cli_state *cli,
3416 : const char *path,
3417 : uint16_t *pattr)
3418 : {
3419 0 : uint8_t *bytes = NULL;
3420 0 : uint16_t *return_words = NULL;
3421 0 : uint8_t return_wcount = 0;
3422 0 : NTSTATUS status;
3423 :
3424 0 : bytes = talloc_array(talloc_tos(), uint8_t, 1);
3425 0 : if (bytes == NULL) {
3426 0 : return NT_STATUS_NO_MEMORY;
3427 : }
3428 0 : bytes[0] = 4;
3429 0 : bytes = smb_bytes_push_str(bytes,
3430 0 : smbXcli_conn_use_unicode(cli->conn),
3431 : path,
3432 0 : strlen(path)+1,
3433 : NULL);
3434 0 : if (bytes == NULL) {
3435 0 : return NT_STATUS_NO_MEMORY;
3436 : }
3437 :
3438 0 : status = cli_smb(talloc_tos(),
3439 : cli,
3440 : SMBgetatr, /* command. */
3441 : 0, /* additional_flags. */
3442 : 0, /* wct. */
3443 : NULL, /* vwv. */
3444 0 : talloc_get_size(bytes), /* num_bytes. */
3445 : bytes, /* bytes. */
3446 : NULL, /* result parent. */
3447 : 10, /* min_wct. */
3448 : &return_wcount, /* return wcount. */
3449 : &return_words, /* return wvw. */
3450 : NULL, /* return byte count. */
3451 : NULL); /* return bytes. */
3452 0 : if (!NT_STATUS_IS_OK(status)) {
3453 0 : return status;
3454 : }
3455 0 : *pattr = PULL_LE_U16(return_words, 0);
3456 0 : return status;
3457 : }
3458 :
3459 0 : static bool test_smb1_getatr(struct cli_state *cli)
3460 : {
3461 0 : NTSTATUS status;
3462 0 : bool retval = false;
3463 0 : bool ok = false;
3464 0 : uint16_t attrs = 0;
3465 :
3466 : /* Start clean. */
3467 0 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\getatrfile");
3468 :
3469 : /* Create a test file. */
3470 0 : ok = smb1_create_testfile(cli, "\\BAD\\BAD\\getatrfile");
3471 0 : if (!ok) {
3472 0 : printf("%s:%d failed to create test file %s\n",
3473 : __FILE__,
3474 : __LINE__,
3475 : "\\BAD\\BAD\\getatrfile");
3476 0 : goto err;
3477 : }
3478 :
3479 : /*
3480 : * We expect this to succeed, but get attributes of
3481 : * the root directory.
3482 : */
3483 0 : status = smb1_getatr(cli, "getatrfile", &attrs);
3484 0 : if (!NT_STATUS_IS_OK(status)) {
3485 0 : printf("%s:%d SMB1getatr of %s failed (%s)\n",
3486 : __FILE__,
3487 : __LINE__,
3488 : "getatrfile",
3489 : nt_errstr(status));
3490 0 : goto err;
3491 : }
3492 0 : if ((attrs & FILE_ATTRIBUTE_DIRECTORY) == 0) {
3493 0 : printf("%s:%d error expected SMB1getatr of file %s "
3494 : "to return directory attributes. Got 0x%x\n",
3495 : __FILE__,
3496 : __LINE__,
3497 : "getatrfile",
3498 : (unsigned int)attrs);
3499 0 : goto err;
3500 : }
3501 :
3502 : /*
3503 : * We expect this to succeed, but get attributes of
3504 : * the root directory.
3505 : */
3506 0 : status = smb1_getatr(cli, "\\BAD\\getatrfile", &attrs);
3507 0 : if (!NT_STATUS_IS_OK(status)) {
3508 0 : printf("%s:%d SMB1getatr of %s failed (%s)\n",
3509 : __FILE__,
3510 : __LINE__,
3511 : "\\BAD\\getatrfile",
3512 : nt_errstr(status));
3513 0 : goto err;
3514 : }
3515 0 : if ((attrs & FILE_ATTRIBUTE_DIRECTORY) == 0) {
3516 0 : printf("%s:%d error expected SMB1getatr of file %s "
3517 : "to return directory attributes. Got 0x%x\n",
3518 : __FILE__,
3519 : __LINE__,
3520 : "\\BAD\\getatrfile",
3521 : (unsigned int)attrs);
3522 0 : goto err;
3523 : }
3524 :
3525 : /*
3526 : * We expect this to succeed, and get attributes of
3527 : * the testfile.
3528 : */
3529 0 : status = smb1_getatr(cli, "\\BAD\\BAD\\getatrfile", &attrs);
3530 0 : if (!NT_STATUS_IS_OK(status)) {
3531 0 : printf("%s:%d SMB1getatr of %s failed (%s)\n",
3532 : __FILE__,
3533 : __LINE__,
3534 : "\\BAD\\BAD\\getatrfile",
3535 : nt_errstr(status));
3536 0 : goto err;
3537 : }
3538 0 : if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
3539 0 : printf("%s:%d error expected SMB1getatr of file %s "
3540 : "to return non-directory attributes. Got 0x%x\n",
3541 : __FILE__,
3542 : __LINE__,
3543 : "\\BAD\\BAD\\getatrfile",
3544 : (unsigned int)attrs);
3545 0 : goto err;
3546 : }
3547 :
3548 0 : retval = true;
3549 :
3550 0 : err:
3551 :
3552 0 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\getatrfile");
3553 0 : return retval;
3554 : }
3555 :
3556 0 : static NTSTATUS smb1_setatr(struct cli_state *cli,
3557 : const char *path,
3558 : uint16_t attr)
3559 : {
3560 0 : uint16_t vwv[8] = { 0 };
3561 0 : uint8_t *bytes = NULL;
3562 0 : NTSTATUS status;
3563 :
3564 0 : PUSH_LE_U16(vwv, 0, attr);
3565 0 : bytes = talloc_array(talloc_tos(), uint8_t, 1);
3566 0 : if (bytes == NULL) {
3567 0 : return NT_STATUS_NO_MEMORY;
3568 : }
3569 0 : bytes[0] = 4;
3570 0 : bytes = smb_bytes_push_str(bytes,
3571 0 : smbXcli_conn_use_unicode(cli->conn),
3572 : path,
3573 0 : strlen(path)+1,
3574 : NULL);
3575 0 : if (bytes == NULL) {
3576 0 : return NT_STATUS_NO_MEMORY;
3577 : }
3578 0 : status = cli_smb(talloc_tos(),
3579 : cli,
3580 : SMBsetatr, /* command. */
3581 : 0, /* additional_flags. */
3582 : 8, /* wct. */
3583 : vwv, /* vwv. */
3584 0 : talloc_get_size(bytes), /* num_bytes. */
3585 : bytes, /* bytes. */
3586 : NULL, /* result parent. */
3587 : 0, /* min_wct. */
3588 : NULL, /* return wcount. */
3589 : NULL, /* return wvw. */
3590 : NULL, /* return byte count. */
3591 : NULL); /* return bytes. */
3592 0 : if (!NT_STATUS_IS_OK(status)) {
3593 0 : return status;
3594 : }
3595 0 : return status;
3596 : }
3597 :
3598 0 : static bool test_smb1_setatr(struct cli_state *cli)
3599 : {
3600 0 : NTSTATUS status;
3601 0 : bool retval = false;
3602 0 : bool ok = false;
3603 0 : uint16_t file_attrs = 0;
3604 0 : uint16_t orig_file_attrs = 0;
3605 :
3606 : /* Start clean. */
3607 0 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\setatrfile");
3608 :
3609 : /* Create a test file. */
3610 0 : ok = smb1_create_testfile(cli, "\\BAD\\BAD\\setatrfile");
3611 0 : if (!ok) {
3612 0 : printf("%s:%d failed to create test file %s\n",
3613 : __FILE__,
3614 : __LINE__,
3615 : "\\BAD\\BAD\\setatrfile");
3616 0 : goto err;
3617 : }
3618 : /* Get it's original attributes. */
3619 0 : status = smb1_getatr(cli, "\\BAD\\BAD\\setatrfile", &orig_file_attrs);
3620 0 : if (!NT_STATUS_IS_OK(status)) {
3621 0 : printf("%s:%d SMB1getatr of %s failed (%s)\n",
3622 : __FILE__,
3623 : __LINE__,
3624 : "\\BAD\\BAD\\setatrfile",
3625 : nt_errstr(status));
3626 0 : goto err;
3627 : }
3628 :
3629 0 : if (orig_file_attrs & FILE_ATTRIBUTE_SYSTEM) {
3630 0 : printf("%s:%d orig_file_attrs of %s already has SYSTEM. "
3631 : "Test cannot proceed.\n",
3632 : __FILE__,
3633 : __LINE__,
3634 : "\\BAD\\BAD\\setatrfile");
3635 0 : goto err;
3636 : }
3637 :
3638 : /*
3639 : * Seems we can't set attrs on the root of a share,
3640 : * even as Administrator.
3641 : */
3642 0 : status = smb1_setatr(cli, "setatrfile", FILE_ATTRIBUTE_SYSTEM);
3643 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
3644 0 : printf("%s:%d SMB1setatr of %s should get "
3645 : "NT_STATUS_ACCESS_DENIED, got %s\n",
3646 : __FILE__,
3647 : __LINE__,
3648 : "setatrfile",
3649 : nt_errstr(status));
3650 0 : goto err;
3651 : }
3652 :
3653 : /*
3654 : * Seems we can't set attrs on the root of a share,
3655 : * even as Administrator.
3656 : */
3657 0 : status = smb1_setatr(cli, "\\BAD\\setatrfile", FILE_ATTRIBUTE_SYSTEM);
3658 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
3659 0 : printf("%s:%d SMB1setatr of %s should get "
3660 : "NT_STATUS_ACCESS_DENIED, got %s\n",
3661 : __FILE__,
3662 : __LINE__,
3663 : "\\BAD\\setatrfile",
3664 : nt_errstr(status));
3665 0 : goto err;
3666 : }
3667 :
3668 0 : status = smb1_setatr(cli,
3669 : "\\BAD\\BAD\\setatrfile",
3670 : FILE_ATTRIBUTE_SYSTEM);
3671 0 : if (!NT_STATUS_IS_OK(status)) {
3672 0 : printf("%s:%d SMB1setatr of %s failed (%s)\n",
3673 : __FILE__,
3674 : __LINE__,
3675 : "\\BAD\\BAD\\setatrfile",
3676 : nt_errstr(status));
3677 0 : goto err;
3678 : }
3679 0 : status = smb1_getatr(cli, "\\BAD\\BAD\\setatrfile", &file_attrs);
3680 0 : if (!NT_STATUS_IS_OK(status)) {
3681 0 : printf("%s:%d SMB1getatr of %s failed (%s)\n",
3682 : __FILE__,
3683 : __LINE__,
3684 : "\\BAD\\BAD\\setatrfile",
3685 : nt_errstr(status));
3686 0 : goto err;
3687 : }
3688 :
3689 0 : if (file_attrs != FILE_ATTRIBUTE_SYSTEM) {
3690 0 : printf("%s:%d Failed to set SYSTEM attr on %s\n",
3691 : __FILE__,
3692 : __LINE__,
3693 : "\\BAD\\BAD\\setatrfile");
3694 0 : goto err;
3695 : }
3696 :
3697 0 : retval = true;
3698 :
3699 0 : err:
3700 :
3701 0 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\setatrfile");
3702 0 : return retval;
3703 : }
3704 :
3705 2 : static NTSTATUS smb1_chkpath(struct cli_state *cli,
3706 : const char *path)
3707 : {
3708 2 : uint8_t *bytes = NULL;
3709 0 : NTSTATUS status;
3710 :
3711 2 : bytes = talloc_array(talloc_tos(), uint8_t, 1);
3712 2 : if (bytes == NULL) {
3713 0 : return NT_STATUS_NO_MEMORY;
3714 : }
3715 2 : bytes[0] = 4;
3716 2 : bytes = smb_bytes_push_str(bytes,
3717 2 : smbXcli_conn_use_unicode(cli->conn),
3718 : path,
3719 2 : strlen(path)+1,
3720 : NULL);
3721 2 : if (bytes == NULL) {
3722 0 : return NT_STATUS_NO_MEMORY;
3723 : }
3724 2 : status = cli_smb(talloc_tos(),
3725 : cli,
3726 : SMBcheckpath, /* command. */
3727 : 0, /* additional_flags. */
3728 : 0, /* wct. */
3729 : NULL, /* vwv. */
3730 2 : talloc_get_size(bytes), /* num_bytes. */
3731 : bytes, /* bytes. */
3732 : NULL, /* result parent. */
3733 : 0, /* min_wct. */
3734 : NULL, /* return wcount. */
3735 : NULL, /* return wvw. */
3736 : NULL, /* return byte count. */
3737 : NULL); /* return bytes. */
3738 2 : if (!NT_STATUS_IS_OK(status)) {
3739 0 : return status;
3740 : }
3741 2 : return status;
3742 : }
3743 :
3744 0 : static bool test_smb1_chkpath(struct cli_state *cli)
3745 : {
3746 0 : NTSTATUS status;
3747 0 : bool retval = false;
3748 0 : bool ok = false;
3749 :
3750 : /* Start clean. */
3751 0 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\chkpathfile");
3752 :
3753 : /* Create a test file. */
3754 0 : ok = smb1_create_testfile(cli, "\\BAD\\BAD\\chkpathfile");
3755 0 : if (!ok) {
3756 0 : printf("%s:%d failed to create test file %s\n",
3757 : __FILE__,
3758 : __LINE__,
3759 : "\\BAD\\BAD\\chkpathfile");
3760 0 : goto err;
3761 : }
3762 : /*
3763 : * Should succeed - "chkpathfile" maps to
3764 : * directory "".
3765 : */
3766 0 : status = smb1_chkpath(cli, "chkpathfile");
3767 0 : if (!NT_STATUS_IS_OK(status)) {
3768 0 : printf("%s:%d SMB1chkpath of %s failed (%s)\n",
3769 : __FILE__,
3770 : __LINE__,
3771 : "chkpathfile",
3772 : nt_errstr(status));
3773 0 : goto err;
3774 : }
3775 :
3776 : /*
3777 : * Should succeed - "\\BAD\\chkpathfile" maps to
3778 : * directory "".
3779 : */
3780 0 : status = smb1_chkpath(cli, "\\BAD\\chkpathfile");
3781 0 : if (!NT_STATUS_IS_OK(status)) {
3782 0 : printf("%s:%d SMB1chkpath of %s failed (%s)\n",
3783 : __FILE__,
3784 : __LINE__,
3785 : "\\BAD\\chkpathfile",
3786 : nt_errstr(status));
3787 0 : goto err;
3788 : }
3789 :
3790 : /*
3791 : * Should fail - "\\BAD\\BAD\\chkpathfile" maps to the
3792 : * "\\BAD\\BAD\\chkpathfile", not a directory.
3793 : */
3794 0 : status = smb1_chkpath(cli, "\\BAD\\BAD\\chkpathfile");
3795 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
3796 0 : printf("%s:%d SMB1chkpath of %s should get "
3797 : "NT_STATUS_NOT_A_DIRECTORY, got %s\n",
3798 : __FILE__,
3799 : __LINE__,
3800 : "\\BAD\\BAD\\chkpathfile",
3801 : nt_errstr(status));
3802 0 : goto err;
3803 : }
3804 :
3805 0 : retval = true;
3806 :
3807 0 : err:
3808 :
3809 0 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\chkpathfile");
3810 0 : return retval;
3811 : }
3812 :
3813 : /*
3814 : * Test BUG: https://bugzilla.samba.org/show_bug.cgi?id=15419
3815 : */
3816 :
3817 2 : static bool test_smb1_chkpath_bad(struct cli_state *cli)
3818 : {
3819 0 : NTSTATUS status;
3820 :
3821 2 : status = smb1_chkpath(cli, "\\x//\\/");
3822 2 : if (!NT_STATUS_IS_OK(status)) {
3823 0 : printf("%s:%d SMB1chkpath of %s failed (%s)\n",
3824 : __FILE__,
3825 : __LINE__,
3826 : "\\x//\\/",
3827 : nt_errstr(status));
3828 0 : return false;
3829 : }
3830 2 : return true;
3831 : }
3832 :
3833 0 : static NTSTATUS smb1_ctemp(struct cli_state *cli,
3834 : const char *path,
3835 : char **tmp_path)
3836 : {
3837 0 : uint16_t vwv[3] = { 0 };
3838 0 : uint8_t *bytes = NULL;
3839 0 : NTSTATUS status;
3840 0 : uint16_t *return_words = NULL;
3841 0 : uint8_t return_wcount = 0;
3842 0 : uint32_t return_bytecount = 0;
3843 0 : uint8_t *return_bytes = NULL;
3844 0 : size_t sret = 0;
3845 0 : uint16_t fnum = (uint16_t)-1;
3846 :
3847 0 : bytes = talloc_array(talloc_tos(), uint8_t, 1);
3848 0 : if (bytes == NULL) {
3849 0 : return NT_STATUS_NO_MEMORY;
3850 : }
3851 0 : bytes[0] = 4;
3852 0 : bytes = smb_bytes_push_str(bytes,
3853 0 : smbXcli_conn_use_unicode(cli->conn),
3854 : path,
3855 0 : strlen(path)+1,
3856 : NULL);
3857 0 : if (bytes == NULL) {
3858 0 : return NT_STATUS_NO_MEMORY;
3859 : }
3860 0 : status = cli_smb(talloc_tos(),
3861 : cli,
3862 : SMBctemp, /* command. */
3863 : 0, /* additional_flags. */
3864 : 3, /* wct. */
3865 : vwv, /* vwv. */
3866 0 : talloc_get_size(bytes), /* num_bytes. */
3867 : bytes, /* bytes. */
3868 : NULL, /* result parent. */
3869 : 1, /* min_wct. */
3870 : &return_wcount, /* return wcount. */
3871 : &return_words, /* return wvw. */
3872 : &return_bytecount, /* return byte count. */
3873 : &return_bytes); /* return bytes. */
3874 0 : if (!NT_STATUS_IS_OK(status)) {
3875 0 : return status;
3876 : }
3877 :
3878 0 : if (return_wcount != 1) {
3879 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
3880 : }
3881 :
3882 0 : fnum = PULL_LE_U16(return_words, 0);
3883 :
3884 : /* Delete the file by fnum. */
3885 0 : status = cli_nt_delete_on_close(cli, fnum, 1);
3886 0 : if (!NT_STATUS_IS_OK(status)) {
3887 0 : return status;
3888 : }
3889 0 : (void)smb1cli_close(cli->conn,
3890 0 : cli->timeout,
3891 : cli->smb1.pid,
3892 : cli->smb1.tcon,
3893 : cli->smb1.session,
3894 : fnum,
3895 : 0); /* last_modified */
3896 0 : fnum = (uint16_t)-1;
3897 :
3898 0 : if (return_bytecount < 2) {
3899 0 : return NT_STATUS_DATA_ERROR;
3900 : }
3901 :
3902 0 : sret = pull_string_talloc(talloc_tos(),
3903 : NULL,
3904 : 0,
3905 : tmp_path,
3906 : return_bytes,
3907 : return_bytecount,
3908 : STR_ASCII);
3909 0 : if (sret == 0) {
3910 0 : return NT_STATUS_NO_MEMORY;
3911 : }
3912 :
3913 0 : return status;
3914 : }
3915 :
3916 0 : static bool test_smb1_ctemp(struct cli_state *cli)
3917 : {
3918 0 : NTSTATUS status;
3919 0 : bool retval = false;
3920 0 : char *retpath = NULL;
3921 :
3922 : /* Start clean. */
3923 0 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\ctemp_dir");
3924 :
3925 0 : status = smb1_mkdir(cli, "\\BAD\\BAD\\ctemp_dir");
3926 0 : if (!NT_STATUS_IS_OK(status)) {
3927 0 : printf("%s:%d Failed to create %s (%s)\n",
3928 : __FILE__,
3929 : __LINE__,
3930 : "\\BAD\\BAD\\ctemp_dir",
3931 : nt_errstr(status));
3932 0 : goto err;
3933 : }
3934 :
3935 : /*
3936 : * Windows returns NT_STATUS_FILE_IS_A_DIRECTORY
3937 : * for all SMBctemp calls on a DFS share, no
3938 : * matter what we put in the pathname.
3939 : */
3940 :
3941 : /*
3942 : * When we fix smbd we'll need to detect running
3943 : * in smbtorture3 against smbd here and modify
3944 : * the expected behavior. Windows is simply
3945 : * broken here.
3946 : */
3947 0 : status = smb1_ctemp(cli, "ctemp_dir", &retpath);
3948 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
3949 0 : printf("%s:%d SMB1ctemp of %s should get "
3950 : "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3951 : __FILE__,
3952 : __LINE__,
3953 : "ctemp_dir",
3954 : nt_errstr(status));
3955 0 : goto err;
3956 : }
3957 0 : status = smb1_ctemp(cli, "\\BAD\\ctemp_dir", &retpath);
3958 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
3959 0 : printf("%s:%d SMB1ctemp of %s should get "
3960 : "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3961 : __FILE__,
3962 : __LINE__,
3963 : "\\BAD\\ctemp_dir",
3964 : nt_errstr(status));
3965 0 : goto err;
3966 : }
3967 0 : status = smb1_ctemp(cli, "\\BAD\\BAD\\ctemp_dir", &retpath);
3968 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
3969 0 : printf("%s:%d SMB1ctemp of %s should get "
3970 : "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3971 : __FILE__,
3972 : __LINE__,
3973 : "\\BAD\\BAD\\ctemp_dir",
3974 : nt_errstr(status));
3975 0 : goto err;
3976 : }
3977 :
3978 0 : retval = true;
3979 :
3980 0 : err:
3981 :
3982 0 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\ctemp_dir");
3983 0 : return retval;
3984 : }
3985 :
3986 0 : static NTSTATUS smb1_qpathinfo(struct cli_state *cli,
3987 : const char *fname,
3988 : uint32_t *pattrs)
3989 : {
3990 0 : NTSTATUS status;
3991 0 : uint8_t *param = NULL;
3992 0 : uint16_t setup[1] = { 0 };
3993 0 : uint8_t *rdata = NULL;
3994 0 : uint32_t num_rdata = 0;
3995 :
3996 0 : PUSH_LE_U16(setup, 0, TRANSACT2_QPATHINFO);
3997 :
3998 0 : param = talloc_zero_array(talloc_tos(), uint8_t, 6);
3999 0 : if (param == NULL) {
4000 0 : return NT_STATUS_NO_MEMORY;
4001 : }
4002 0 : PUSH_LE_U16(param, 0, SMB_QUERY_FILE_BASIC_INFO);
4003 :
4004 0 : param = trans2_bytes_push_str(param,
4005 0 : smbXcli_conn_use_unicode(cli->conn),
4006 : fname,
4007 0 : strlen(fname)+1,
4008 : NULL);
4009 0 : if (param == NULL) {
4010 0 : return NT_STATUS_NO_MEMORY;
4011 : }
4012 :
4013 0 : status = cli_trans(talloc_tos(),
4014 : cli,
4015 : SMBtrans2, /* cmd */
4016 : NULL, /* pipe_name */
4017 : 0, /* fid */
4018 : 0, /* function */
4019 : 0, /* flags */
4020 : &setup[0],
4021 : 1, /* num_setup uint16_t words */
4022 : 0, /* max returned setup */
4023 : param,
4024 0 : talloc_get_size(param), /* num_param */
4025 : 2, /* max returned param */
4026 : NULL, /* data */
4027 : 0, /* num_data */
4028 : SMB_BUFFER_SIZE_MAX, /* max returned data */
4029 : /* Return values from here on.. */
4030 : NULL, /* recv_flags2 */
4031 : NULL, /* rsetup */
4032 : 0, /* min returned rsetup */
4033 : NULL, /* num_rsetup */
4034 : NULL,
4035 : 0, /* min returned rparam */
4036 : NULL, /* number of returned rparam */
4037 : &rdata,
4038 : 36, /* min returned rdata */
4039 : &num_rdata);
4040 0 : if (!NT_STATUS_IS_OK(status)) {
4041 0 : return status;
4042 : }
4043 0 : *pattrs = PULL_LE_U32(rdata, 32);
4044 0 : return NT_STATUS_OK;
4045 : }
4046 :
4047 0 : static bool test_smb1_qpathinfo(struct cli_state *cli)
4048 : {
4049 0 : NTSTATUS status;
4050 0 : bool retval = false;
4051 0 : bool ok = false;
4052 0 : uint32_t attrs;
4053 :
4054 : /* Start clean. */
4055 0 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\qpathinfo_file");
4056 :
4057 : /* Create a test file. */
4058 0 : ok = smb1_create_testfile(cli, "\\BAD\\BAD\\qpathinfo_file");
4059 0 : if (!ok) {
4060 0 : printf("%s:%d failed to create test file %s\n",
4061 : __FILE__,
4062 : __LINE__,
4063 : "\\BAD\\BAD\\qpathinfo_file");
4064 0 : goto err;
4065 : }
4066 :
4067 : /* Should get root dir attrs. */
4068 0 : status = smb1_qpathinfo(cli, "qpathinfo_file", &attrs);
4069 0 : if (!NT_STATUS_IS_OK(status)) {
4070 0 : printf("%s:%d smb1_qpathinfo failed %s (%s)\n",
4071 : __FILE__,
4072 : __LINE__,
4073 : "qpathinfo_file",
4074 : nt_errstr(status));
4075 0 : goto err;
4076 : }
4077 0 : if ((attrs & FILE_ATTRIBUTE_DIRECTORY) == 0) {
4078 0 : printf("%s:%d expected FILE_ATTRIBUTE_DIRECTORY on %s "
4079 : "got attribute 0x%x\n",
4080 : __FILE__,
4081 : __LINE__,
4082 : "qpathinfo_file",
4083 : (unsigned int)attrs);
4084 0 : goto err;
4085 : }
4086 :
4087 : /* Should get root dir attrs. */
4088 0 : status = smb1_qpathinfo(cli, "\\BAD\\qpathinfo_file", &attrs);
4089 0 : if (!NT_STATUS_IS_OK(status)) {
4090 0 : printf("%s:%d smb1_qpathinfo failed %s (%s)\n",
4091 : __FILE__,
4092 : __LINE__,
4093 : "\\BAD\\qpathinfo_file",
4094 : nt_errstr(status));
4095 0 : goto err;
4096 : }
4097 0 : if ((attrs & FILE_ATTRIBUTE_DIRECTORY) == 0) {
4098 0 : printf("%s:%d expected FILE_ATTRIBUTE_DIRECTORY on %s "
4099 : "got attribute 0x%x\n",
4100 : __FILE__,
4101 : __LINE__,
4102 : "\\BAD\\qpathinfo_file",
4103 : (unsigned int)attrs);
4104 0 : goto err;
4105 : }
4106 :
4107 : /* Should get file attrs. */
4108 0 : status = smb1_qpathinfo(cli, "\\BAD\\BAD\\qpathinfo_file", &attrs);
4109 0 : if (!NT_STATUS_IS_OK(status)) {
4110 0 : printf("%s:%d smb1_qpathinfo failed %s (%s)\n",
4111 : __FILE__,
4112 : __LINE__,
4113 : "\\BAD\\BAD\\qpathinfo_file",
4114 : nt_errstr(status));
4115 0 : goto err;
4116 : }
4117 0 : if ((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0) {
4118 0 : printf("%s:%d expected not FILE_ATTRIBUTE_DIRECTORY on %s "
4119 : "got attribute 0x%x\n",
4120 : __FILE__,
4121 : __LINE__,
4122 : "\\BAD\\BAD\\qpathinfo_file",
4123 : (unsigned int)attrs);
4124 : }
4125 :
4126 0 : retval = true;
4127 :
4128 0 : err:
4129 :
4130 0 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\qpathinfo_file");
4131 0 : return retval;
4132 : }
4133 :
4134 : /*
4135 : * "Raw" test of different SMB1 operations to a DFS share.
4136 : * We must (mostly) use the lower level smb1cli_XXXX() interfaces,
4137 : * not the cli_XXX() ones here as the ultimate goal is to fix our
4138 : * cli_XXX() interfaces to work transparently over DFS.
4139 : *
4140 : * So here, we're testing the server code, not the client code.
4141 : *
4142 : * Passes cleanly against Windows.
4143 : */
4144 :
4145 2 : bool run_smb1_dfs_operations(int dummy)
4146 : {
4147 2 : struct cli_state *cli = NULL;
4148 2 : bool dfs_supported = false;
4149 2 : bool retval = false;
4150 2 : bool ok = false;
4151 :
4152 2 : printf("Starting SMB1-DFS-OPS\n");
4153 :
4154 2 : if (!torture_init_connection(&cli)) {
4155 0 : return false;
4156 : }
4157 :
4158 2 : if (!torture_open_connection(&cli, 0)) {
4159 0 : return false;
4160 : }
4161 :
4162 : /* Ensure this is a DFS share. */
4163 2 : dfs_supported = smbXcli_conn_dfs_supported(cli->conn);
4164 2 : if (!dfs_supported) {
4165 0 : printf("Server %s does not support DFS\n",
4166 0 : smbXcli_conn_remote_name(cli->conn));
4167 0 : return false;
4168 : }
4169 2 : dfs_supported = smbXcli_tcon_is_dfs_share(cli->smb1.tcon);
4170 2 : if (!dfs_supported) {
4171 0 : printf("Share %s does not support DFS\n",
4172 0 : cli->share);
4173 0 : return false;
4174 : }
4175 :
4176 2 : ok = test_smb1_unlink(cli);
4177 2 : if (!ok) {
4178 0 : goto err;
4179 : }
4180 :
4181 2 : ok = test_smb1_mkdir(cli);
4182 2 : if (!ok) {
4183 0 : goto err;
4184 : }
4185 :
4186 2 : ok = test_smb1_rmdir(cli);
4187 2 : if (!ok) {
4188 0 : goto err;
4189 : }
4190 :
4191 2 : ok = test_smb1_ntcreatex(cli);
4192 2 : if (!ok) {
4193 0 : goto err;
4194 : }
4195 :
4196 2 : ok = test_smb1_nttrans_create(cli);
4197 2 : if (!ok) {
4198 0 : goto err;
4199 : }
4200 :
4201 2 : ok = test_smb1_openx(cli);
4202 2 : if (!ok) {
4203 0 : goto err;
4204 : }
4205 :
4206 2 : ok = test_smb1_open(cli);
4207 2 : if (!ok) {
4208 0 : goto err;
4209 : }
4210 :
4211 2 : ok = test_smb1_create(cli);
4212 2 : if (!ok) {
4213 2 : goto err;
4214 : }
4215 :
4216 0 : ok = test_smb1_getatr(cli);
4217 0 : if (!ok) {
4218 0 : goto err;
4219 : }
4220 :
4221 0 : ok = test_smb1_setatr(cli);
4222 0 : if (!ok) {
4223 0 : goto err;
4224 : }
4225 :
4226 0 : ok = test_smb1_chkpath(cli);
4227 0 : if (!ok) {
4228 0 : goto err;
4229 : }
4230 :
4231 0 : ok = test_smb1_ctemp(cli);
4232 0 : if (!ok) {
4233 0 : goto err;
4234 : }
4235 :
4236 0 : ok = test_smb1_qpathinfo(cli);
4237 0 : if (!ok) {
4238 0 : goto err;
4239 : }
4240 :
4241 0 : retval = true;
4242 :
4243 2 : err:
4244 :
4245 : /* Delete anything we made. */
4246 2 : (void)smb1_dfs_delete(cli, "\\BAD\\BAD\\file");
4247 2 : return retval;
4248 : }
4249 :
4250 : /*
4251 : * Test BUG: https://bugzilla.samba.org/show_bug.cgi?id=15419
4252 : */
4253 :
4254 2 : bool run_smb1_dfs_check_badpath(int dummy)
4255 : {
4256 2 : struct cli_state *cli = NULL;
4257 2 : bool dfs_supported = false;
4258 :
4259 2 : printf("Starting SMB1-DFS-CHECK-BADPATH\n");
4260 :
4261 2 : if (!torture_init_connection(&cli)) {
4262 0 : return false;
4263 : }
4264 :
4265 2 : if (!torture_open_connection(&cli, 0)) {
4266 0 : return false;
4267 : }
4268 :
4269 : /* Ensure this is a DFS share. */
4270 2 : dfs_supported = smbXcli_conn_dfs_supported(cli->conn);
4271 2 : if (!dfs_supported) {
4272 0 : printf("Server %s does not support DFS\n",
4273 0 : smbXcli_conn_remote_name(cli->conn));
4274 0 : return false;
4275 : }
4276 2 : dfs_supported = smbXcli_tcon_is_dfs_share(cli->smb1.tcon);
4277 2 : if (!dfs_supported) {
4278 0 : printf("Share %s does not support DFS\n",
4279 0 : cli->share);
4280 0 : return false;
4281 : }
4282 :
4283 2 : return test_smb1_chkpath_bad(cli);
4284 : }
|