s3: smbtorture3: Add new SMB2-DFS-SHARE-NON-DFS-PATH test.
[samba.git] / source3 / torture / test_smb2.c
1 /*
2    Unix SMB/CIFS implementation.
3    Initial test for the smb2 client lib
4    Copyright (C) Volker Lendecke 2011
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 "libsmb/cli_smb2_fnum.h"
33
34 extern fstring host, workgroup, share, password, username, myname;
35 extern struct cli_credentials *torture_creds;
36
37 bool run_smb2_basic(int dummy)
38 {
39         struct cli_state *cli;
40         NTSTATUS status;
41         uint64_t fid_persistent, fid_volatile;
42         const char *hello = "Hello, world\n";
43         uint8_t *result;
44         uint32_t nread;
45         uint8_t *dir_data;
46         uint32_t dir_data_length;
47         uint32_t saved_tid = 0;
48         struct smbXcli_tcon *saved_tcon = NULL;
49         char *saved_share = NULL;
50         uint64_t saved_uid = 0;
51
52         printf("Starting SMB2-BASIC\n");
53
54         if (!torture_init_connection(&cli)) {
55                 return false;
56         }
57
58         status = smbXcli_negprot(cli->conn, cli->timeout,
59                                  PROTOCOL_SMB2_02, PROTOCOL_SMB2_02);
60         if (!NT_STATUS_IS_OK(status)) {
61                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
62                 return false;
63         }
64
65         status = cli_session_setup_creds(cli, torture_creds);
66         if (!NT_STATUS_IS_OK(status)) {
67                 printf("cli_session_setup returned %s\n", nt_errstr(status));
68                 return false;
69         }
70
71         status = cli_tree_connect(cli, share, "?????", NULL);
72         if (!NT_STATUS_IS_OK(status)) {
73                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
74                 return false;
75         }
76
77         status = smb2cli_create(cli->conn, cli->timeout, cli->smb2.session,
78                         cli->smb2.tcon, "smb2-basic.txt",
79                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
80                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
81                         SEC_STD_ALL | SEC_FILE_ALL, /* desired_access, */
82                         FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
83                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
84                         FILE_CREATE, /* create_disposition, */
85                         FILE_DELETE_ON_CLOSE, /* create_options, */
86                         NULL, /* smb2_create_blobs *blobs */
87                         &fid_persistent,
88                         &fid_volatile,
89                         NULL, NULL, NULL);
90         if (!NT_STATUS_IS_OK(status)) {
91                 printf("smb2cli_create returned %s\n", nt_errstr(status));
92                 return false;
93         }
94
95         status = smb2cli_write(cli->conn, cli->timeout, cli->smb2.session,
96                                cli->smb2.tcon, strlen(hello), 0, fid_persistent,
97                                fid_volatile, 0, 0, (const uint8_t *)hello, NULL);
98         if (!NT_STATUS_IS_OK(status)) {
99                 printf("smb2cli_write returned %s\n", nt_errstr(status));
100                 return false;
101         }
102
103         status = smb2cli_flush(cli->conn, cli->timeout, cli->smb2.session,
104                                cli->smb2.tcon, fid_persistent, fid_volatile);
105         if (!NT_STATUS_IS_OK(status)) {
106                 printf("smb2cli_flush returned %s\n", nt_errstr(status));
107                 return false;
108         }
109
110         status = smb2cli_read(cli->conn, cli->timeout, cli->smb2.session,
111                               cli->smb2.tcon, 0x10000, 0, fid_persistent,
112                               fid_volatile, 2, 0,
113                               talloc_tos(), &result, &nread);
114         if (!NT_STATUS_IS_OK(status)) {
115                 printf("smb2cli_read returned %s\n", nt_errstr(status));
116                 return false;
117         }
118
119         if (nread != strlen(hello)) {
120                 printf("smb2cli_read returned %d bytes, expected %d\n",
121                        (int)nread, (int)strlen(hello));
122                 return false;
123         }
124
125         if (memcmp(hello, result, nread) != 0) {
126                 printf("smb2cli_read returned '%s', expected '%s'\n",
127                        result, hello);
128                 return false;
129         }
130
131         status = smb2cli_close(cli->conn, cli->timeout, cli->smb2.session,
132                                cli->smb2.tcon, 0, fid_persistent, fid_volatile);
133         if (!NT_STATUS_IS_OK(status)) {
134                 printf("smb2cli_close returned %s\n", nt_errstr(status));
135                 return false;
136         }
137
138         status = smb2cli_create(cli->conn, cli->timeout, cli->smb2.session,
139                         cli->smb2.tcon, "",
140                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
141                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
142                         SEC_STD_SYNCHRONIZE|
143                         SEC_DIR_LIST|
144                         SEC_DIR_READ_ATTRIBUTE, /* desired_access, */
145                         0, /* file_attributes, */
146                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
147                         FILE_OPEN, /* create_disposition, */
148                         FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE, /* create_options, */
149                         NULL, /* smb2_create_blobs *blobs */
150                         &fid_persistent,
151                         &fid_volatile,
152                         NULL, NULL, NULL);
153         if (!NT_STATUS_IS_OK(status)) {
154                 printf("smb2cli_create returned %s\n", nt_errstr(status));
155                 return false;
156         }
157
158         status = smb2cli_query_directory(
159                 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
160                 1, 0, 0, fid_persistent, fid_volatile, "*", 0xffff,
161                 talloc_tos(), &dir_data, &dir_data_length);
162
163         if (!NT_STATUS_IS_OK(status)) {
164                 printf("smb2cli_query_directory returned %s\n", nt_errstr(status));
165                 return false;
166         }
167
168         status = smb2cli_close(cli->conn, cli->timeout, cli->smb2.session,
169                                cli->smb2.tcon, 0, fid_persistent, fid_volatile);
170         if (!NT_STATUS_IS_OK(status)) {
171                 printf("smb2cli_close returned %s\n", nt_errstr(status));
172                 return false;
173         }
174
175         saved_tid = smb2cli_tcon_current_id(cli->smb2.tcon);
176         cli_state_save_tcon_share(cli, &saved_tcon, &saved_share);
177         cli->smb2.tcon = smbXcli_tcon_create(cli);
178         smb2cli_tcon_set_values(cli->smb2.tcon,
179                                 NULL, /* session */
180                                 saved_tid,
181                                 0, /* type */
182                                 0, /* flags */
183                                 0, /* capabilities */
184                                 0  /* maximal_access */);
185         status = smb2cli_tdis(cli->conn,
186                               cli->timeout,
187                               cli->smb2.session,
188                               cli->smb2.tcon);
189         cli_state_restore_tcon_share(cli, saved_tcon, saved_share);
190         if (!NT_STATUS_IS_OK(status)) {
191                 printf("smb2cli_tdis returned %s\n", nt_errstr(status));
192                 return false;
193         }
194
195         status = smb2cli_tdis(cli->conn,
196                               cli->timeout,
197                               cli->smb2.session,
198                               cli->smb2.tcon);
199         if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED)) {
200                 printf("2nd smb2cli_tdis returned %s\n", nt_errstr(status));
201                 return false;
202         }
203
204         saved_uid = smb2cli_session_current_id(cli->smb2.session);
205         status = smb2cli_logoff(cli->conn, cli->timeout, cli->smb2.session);
206         if (!NT_STATUS_IS_OK(status)) {
207                 printf("smb2cli_logoff returned %s\n", nt_errstr(status));
208                 return false;
209         }
210
211         cli->smb2.session = smbXcli_session_create(cli, cli->conn);
212         if (cli->smb2.session == NULL) {
213                 printf("smbXcli_session_create() returned NULL\n");
214                 return false;
215         }
216
217         smb2cli_session_set_id_and_flags(cli->smb2.session, saved_uid, 0);
218
219         status = smb2cli_logoff(cli->conn, cli->timeout, cli->smb2.session);
220         if (!NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
221                 printf("2nd smb2cli_logoff returned %s\n", nt_errstr(status));
222                 return false;
223         }
224
225         return true;
226 }
227
228 bool run_smb2_negprot(int dummy)
229 {
230         struct cli_state *cli;
231         NTSTATUS status;
232         enum protocol_types protocol;
233         const char *name = NULL;
234
235         printf("Starting SMB2-NEGPROT\n");
236
237         if (!torture_init_connection(&cli)) {
238                 return false;
239         }
240
241         status = smbXcli_negprot(cli->conn, cli->timeout,
242                                  PROTOCOL_CORE, PROTOCOL_LATEST);
243         if (!NT_STATUS_IS_OK(status)) {
244                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
245                 return false;
246         }
247
248         protocol = smbXcli_conn_protocol(cli->conn);
249         name = smb_protocol_types_string(protocol);
250
251         if (protocol >= PROTOCOL_SMB2_02) {
252                 printf("Server supports %s\n", name);
253         } else {
254                 printf("Server DOES NOT support SMB2, only %s\n", name);
255                 return false;
256         }
257
258         status = smbXcli_negprot(cli->conn, cli->timeout,
259                                  protocol, protocol);
260         if (!NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_RESET) &&
261             !NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_DISCONNECTED) &&
262             !NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_ABORTED)) {
263                 printf("2nd smbXcli_negprot should disconnect - returned %s\n",
264                         nt_errstr(status));
265                 return false;
266         }
267
268         if (smbXcli_conn_is_connected(cli->conn)) {
269                 printf("2nd smbXcli_negprot should disconnect "
270                        "- still connected\n");
271                 return false;
272         }
273
274         return true;
275 }
276
277 bool run_smb2_anonymous(int dummy)
278 {
279         struct cli_state *cli = NULL;
280         NTSTATUS status;
281         struct cli_credentials *anon_creds = NULL;
282         bool guest = false;
283
284         printf("Starting SMB2-ANONYMOUS\n");
285
286         if (!torture_init_connection(&cli)) {
287                 return false;
288         }
289
290         status = smbXcli_negprot(cli->conn, cli->timeout,
291                                  PROTOCOL_SMB2_02, PROTOCOL_LATEST);
292         if (!NT_STATUS_IS_OK(status)) {
293                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
294                 return false;
295         }
296
297         anon_creds = cli_credentials_init_anon(talloc_tos());
298         if (anon_creds == NULL) {
299                 printf("cli_credentials_init_anon failed\n");
300                 return false;
301         }
302
303         status = cli_session_setup_creds(cli, anon_creds);
304         if (!NT_STATUS_IS_OK(status)) {
305                 printf("cli_session_setup returned %s\n", nt_errstr(status));
306                 return false;
307         }
308
309         guest = smbXcli_session_is_guest(cli->smb2.session);
310         if (guest) {
311                 printf("anonymous session should not have guest authentication\n");
312                 return false;
313         }
314
315         return true;
316 }
317
318 bool run_smb2_session_reconnect(int dummy)
319 {
320         struct cli_state *cli1;
321         struct cli_state *cli2;
322         NTSTATUS status;
323         bool ok;
324         uint64_t fid_persistent, fid_volatile;
325         struct tevent_context *ev;
326         struct tevent_req *subreq;
327         DATA_BLOB in_blob = data_blob_null;
328         DATA_BLOB out_blob;
329         DATA_BLOB session_key;
330         struct auth_generic_state *auth_generic_state;
331         struct iovec *recv_iov;
332         const char *hello = "Hello, world\n";
333         uint8_t *result;
334         uint32_t nread;
335
336         printf("Starting SMB2-SESSION-RECONNECT\n");
337
338         if (!torture_init_connection(&cli1)) {
339                 return false;
340         }
341
342         status = smbXcli_negprot(cli1->conn, cli1->timeout,
343                                  PROTOCOL_SMB2_02, PROTOCOL_LATEST);
344         if (!NT_STATUS_IS_OK(status)) {
345                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
346                 return false;
347         }
348
349         status = cli_session_setup_creds(cli1, torture_creds);
350         if (!NT_STATUS_IS_OK(status)) {
351                 printf("cli_session_setup returned %s\n", nt_errstr(status));
352                 return false;
353         }
354
355         status = cli_tree_connect(cli1, share, "?????", NULL);
356         if (!NT_STATUS_IS_OK(status)) {
357                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
358                 return false;
359         }
360
361         status = smb2cli_create(cli1->conn, cli1->timeout, cli1->smb2.session,
362                         cli1->smb2.tcon, "session-reconnect.txt",
363                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
364                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
365                         SEC_STD_ALL | SEC_FILE_ALL, /* desired_access, */
366                         FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
367                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
368                         FILE_CREATE, /* create_disposition, */
369                         FILE_DELETE_ON_CLOSE, /* create_options, */
370                         NULL, /* smb2_create_blobs *blobs */
371                         &fid_persistent,
372                         &fid_volatile,
373                         NULL, NULL, NULL);
374         if (!NT_STATUS_IS_OK(status)) {
375                 printf("smb2cli_create on cli1 %s\n", nt_errstr(status));
376                 return false;
377         }
378
379         status = smb2cli_write(cli1->conn, cli1->timeout, cli1->smb2.session,
380                                cli1->smb2.tcon, strlen(hello), 0, fid_persistent,
381                                fid_volatile, 0, 0, (const uint8_t *)hello, NULL);
382         if (!NT_STATUS_IS_OK(status)) {
383                 printf("smb2cli_write returned %s\n", nt_errstr(status));
384                 return false;
385         }
386
387         status = smb2cli_flush(cli1->conn, cli1->timeout, cli1->smb2.session,
388                                cli1->smb2.tcon, fid_persistent, fid_volatile);
389         if (!NT_STATUS_IS_OK(status)) {
390                 printf("smb2cli_flush returned %s\n", nt_errstr(status));
391                 return false;
392         }
393
394         status = smb2cli_read(cli1->conn, cli1->timeout, cli1->smb2.session,
395                               cli1->smb2.tcon, 0x10000, 0, fid_persistent,
396                               fid_volatile, 2, 0,
397                               talloc_tos(), &result, &nread);
398         if (!NT_STATUS_IS_OK(status)) {
399                 printf("smb2cli_read returned %s\n", nt_errstr(status));
400                 return false;
401         }
402
403         if (nread != strlen(hello)) {
404                 printf("smb2cli_read returned %d bytes, expected %d\n",
405                        (int)nread, (int)strlen(hello));
406                 return false;
407         }
408
409         if (memcmp(hello, result, nread) != 0) {
410                 printf("smb2cli_read returned '%s', expected '%s'\n",
411                        result, hello);
412                 return false;
413         }
414
415         /* prepare second session */
416
417         if (!torture_init_connection(&cli2)) {
418                 return false;
419         }
420
421         status = smbXcli_negprot(cli2->conn, cli2->timeout,
422                                  PROTOCOL_SMB2_02, PROTOCOL_LATEST);
423         if (!NT_STATUS_IS_OK(status)) {
424                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
425                 return false;
426         }
427
428         status = auth_generic_client_prepare(talloc_tos(), &auth_generic_state);
429         if (!NT_STATUS_IS_OK(status)) {
430                 printf("auth_generic_client_prepare returned %s\n", nt_errstr(status));
431                 return false;
432         }
433
434         gensec_want_feature(auth_generic_state->gensec_security,
435                             GENSEC_FEATURE_SESSION_KEY);
436
437         status = auth_generic_set_creds(auth_generic_state, torture_creds);
438         if (!NT_STATUS_IS_OK(status)) {
439                 printf("auth_generic_set_creds returned %s\n", nt_errstr(status));
440                 return false;
441         }
442
443         status = auth_generic_client_start(auth_generic_state, GENSEC_OID_NTLMSSP);
444         if (!NT_STATUS_IS_OK(status)) {
445                 printf("auth_generic_client_start returned %s\n", nt_errstr(status));
446                 return false;
447         }
448
449         ev = samba_tevent_context_init(talloc_tos());
450         if (ev == NULL) {
451                 printf("samba_tevent_context_init() returned NULL\n");
452                 return false;
453         }
454
455         status = gensec_update(auth_generic_state->gensec_security,
456                                talloc_tos(), data_blob_null, &in_blob);
457         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
458                 printf("gensec_update returned %s\n", nt_errstr(status));
459                 return false;
460         }
461
462         cli2->smb2.session = smbXcli_session_create(cli2, cli2->conn);
463
464         subreq = smb2cli_session_setup_send(talloc_tos(), ev,
465                                             cli2->conn,
466                                             cli2->timeout,
467                                             cli2->smb2.session,
468                                             0x0, /* in_flags */
469                                             SMB2_CAP_DFS, /* in_capabilities */
470                                             0, /* in_channel */
471                                             /* in_previous_session_id: */
472                                             smb2cli_session_current_id(cli1->smb2.session),
473                                             &in_blob); /* in_security_buffer */
474         if (subreq == NULL) {
475                 printf("smb2cli_session_setup_send() returned NULL\n");
476                 return false;
477         }
478
479         ok = tevent_req_poll(subreq, ev);
480         if (!ok) {
481                 printf("tevent_req_poll() returned false\n");
482                 return false;
483         }
484
485         status = smb2cli_session_setup_recv(subreq, talloc_tos(),
486                                             NULL, &out_blob);
487         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
488                 printf("smb2cli_session_setup_recv returned %s\n",
489                         nt_errstr(status));
490                 return false;
491         }
492
493         status = gensec_update(auth_generic_state->gensec_security,
494                                talloc_tos(), out_blob, &in_blob);
495         if (!NT_STATUS_IS_OK(status)) {
496                 printf("auth_generic_update returned %s\n", nt_errstr(status));
497                 return false;
498         }
499
500         subreq = smb2cli_session_setup_send(talloc_tos(), ev,
501                                             cli2->conn,
502                                             cli2->timeout,
503                                             cli2->smb2.session,
504                                             0x0, /* in_flags */
505                                             SMB2_CAP_DFS, /* in_capabilities */
506                                             0, /* in_channel */
507                                             /* in_previous_session_id: */
508                                             smb2cli_session_current_id(cli1->smb2.session),
509                                             &in_blob); /* in_security_buffer */
510         if (subreq == NULL) {
511                 printf("smb2cli_session_setup_send() returned NULL\n");
512                 return false;
513         }
514
515         ok = tevent_req_poll(subreq, ev);
516         if (!ok) {
517                 printf("tevent_req_poll() returned false\n");
518                 return false;
519         }
520
521         status = smb2cli_session_setup_recv(subreq, talloc_tos(),
522                                             &recv_iov, &out_blob);
523         if (!NT_STATUS_IS_OK(status)) {
524                 printf("smb2cli_session_setup_recv returned %s\n",
525                         nt_errstr(status));
526                 return false;
527         }
528
529         status = gensec_session_key(auth_generic_state->gensec_security, talloc_tos(),
530                                     &session_key);
531         if (!NT_STATUS_IS_OK(status)) {
532                 printf("gensec_session_key returned %s\n",
533                         nt_errstr(status));
534                 return false;
535         }
536
537         /* check file operation on the old client */
538
539         status = smb2cli_flush(cli1->conn, cli1->timeout, cli1->smb2.session,
540                                cli1->smb2.tcon, fid_persistent, fid_volatile);
541         if (!NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
542                 printf("smb2cli_flush returned %s\n", nt_errstr(status));
543                 return false;
544         }
545
546         status = cli_tree_connect(cli1, share, "?????", NULL);
547         if (!NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
548                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
549                 return false;
550         }
551
552         /*
553          * checking file operations without signing.
554          * on w2k8r2 at least, flush, read and write also work the same way,
555          * while create gives ACCESS_DENIED without signing
556          */
557         status = smb2cli_flush(cli2->conn, cli2->timeout, cli2->smb2.session,
558                                cli2->smb2.tcon, fid_persistent, fid_volatile);
559         if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) &&
560             !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED))
561         {
562                 printf("smb2cli_flush returned %s\n", nt_errstr(status));
563                 return false;
564         }
565
566         status = smb2cli_write(cli2->conn, cli2->timeout, cli2->smb2.session,
567                                cli2->smb2.tcon, strlen(hello), 0, fid_persistent,
568                                fid_volatile, 0, 0, (const uint8_t *)hello, NULL);
569         if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) &&
570             !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED))
571         {
572                 printf("smb2cli_write returned %s\n", nt_errstr(status));
573                 return false;
574         }
575
576         status = smb2cli_read(cli2->conn, cli2->timeout, cli2->smb2.session,
577                               cli2->smb2.tcon, 0x10000, 0, fid_persistent,
578                               fid_volatile, 2, 0,
579                               talloc_tos(), &result, &nread);
580         if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) &&
581             !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED))
582         {
583                 printf("smb2cli_read returned %s\n", nt_errstr(status));
584                 return false;
585         }
586
587         status = smb2cli_create(cli2->conn, cli2->timeout, cli2->smb2.session,
588                         cli2->smb2.tcon, "session-reconnect.txt",
589                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
590                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
591                         SEC_STD_ALL | SEC_FILE_ALL, /* desired_access, */
592                         FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
593                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
594                         FILE_CREATE, /* create_disposition, */
595                         FILE_DELETE_ON_CLOSE, /* create_options, */
596                         NULL, /* smb2_create_blobs *blobs */
597                         &fid_persistent,
598                         &fid_volatile,
599                         NULL, NULL, NULL);
600         if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
601             !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED)) {
602                 printf("smb2cli_create on cli2 %s\n", nt_errstr(status));
603                 return false;
604         }
605
606         /* now grab the session key and try with signing */
607
608         status = smb2cli_session_set_session_key(cli2->smb2.session,
609                                                  session_key,
610                                                  recv_iov);
611         if (!NT_STATUS_IS_OK(status)) {
612                 printf("smb2cli_session_set_session_key %s\n", nt_errstr(status));
613                 return false;
614         }
615
616         /* the tid seems to be irrelevant at this stage */
617
618         status = smb2cli_flush(cli2->conn, cli2->timeout, cli2->smb2.session,
619                                cli1->smb2.tcon, fid_persistent, fid_volatile);
620         if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) &&
621             !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED))
622         {
623                 printf("smb2cli_flush returned %s\n", nt_errstr(status));
624                 return false;
625         }
626
627         status = smb2cli_write(cli2->conn, cli2->timeout, cli2->smb2.session,
628                                cli1->smb2.tcon, strlen(hello), 0, fid_persistent,
629                                fid_volatile, 0, 0, (const uint8_t *)hello, NULL);
630         if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) &&
631             !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED))
632         {
633                 printf("smb2cli_write returned %s\n", nt_errstr(status));
634                 return false;
635         }
636
637         status = smb2cli_read(cli2->conn, cli2->timeout, cli2->smb2.session,
638                               cli1->smb2.tcon, 0x10000, 0, fid_persistent,
639                               fid_volatile, 2, 0,
640                               talloc_tos(), &result, &nread);
641         if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) &&
642             !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED))
643         {
644                 printf("smb2cli_read returned %s\n", nt_errstr(status));
645                 return false;
646         }
647
648         status = smb2cli_create(cli2->conn, cli2->timeout, cli2->smb2.session,
649                         cli1->smb2.tcon, "session-reconnect.txt",
650                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
651                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
652                         SEC_STD_ALL | SEC_FILE_ALL, /* desired_access, */
653                         FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
654                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
655                         FILE_CREATE, /* create_disposition, */
656                         FILE_DELETE_ON_CLOSE, /* create_options, */
657                         NULL, /* smb2_create_blobs *blobs */
658                         &fid_persistent,
659                         &fid_volatile,
660                         NULL, NULL, NULL);
661         if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED) &&
662             !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED))
663         {
664                 printf("smb2cli_create on cli2 %s\n", nt_errstr(status));
665                 return false;
666         }
667
668         /* now do a new tcon and test file calls again */
669
670         status = cli_tree_connect(cli2, share, "?????", NULL);
671         if (!NT_STATUS_IS_OK(status)) {
672                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
673                 return false;
674         }
675
676         status = smb2cli_create(cli2->conn, cli2->timeout, cli2->smb2.session,
677                         cli2->smb2.tcon, "session-reconnect.txt",
678                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
679                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
680                         SEC_STD_ALL | SEC_FILE_ALL, /* desired_access, */
681                         FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
682                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
683                         FILE_CREATE, /* create_disposition, */
684                         FILE_DELETE_ON_CLOSE, /* create_options, */
685                         NULL, /* smb2_create_blobs *blobs */
686                         &fid_persistent,
687                         &fid_volatile,
688                         NULL, NULL, NULL);
689         if (!NT_STATUS_IS_OK(status)) {
690                 printf("smb2cli_create on cli2 %s\n", nt_errstr(status));
691                 return false;
692         }
693
694         status = smb2cli_write(cli2->conn, cli2->timeout, cli2->smb2.session,
695                                cli2->smb2.tcon, strlen(hello), 0, fid_persistent,
696                                fid_volatile, 0, 0, (const uint8_t *)hello, NULL);
697         if (!NT_STATUS_IS_OK(status)) {
698                 printf("smb2cli_write returned %s\n", nt_errstr(status));
699                 return false;
700         }
701
702         status = smb2cli_flush(cli2->conn, cli2->timeout, cli2->smb2.session,
703                                cli2->smb2.tcon, fid_persistent, fid_volatile);
704         if (!NT_STATUS_IS_OK(status)) {
705                 printf("smb2cli_flush returned %s\n", nt_errstr(status));
706                 return false;
707         }
708
709         status = smb2cli_read(cli2->conn, cli2->timeout, cli2->smb2.session,
710                               cli2->smb2.tcon, 0x10000, 0, fid_persistent,
711                               fid_volatile, 2, 0,
712                               talloc_tos(), &result, &nread);
713         if (!NT_STATUS_IS_OK(status)) {
714                 printf("smb2cli_read returned %s\n", nt_errstr(status));
715                 return false;
716         }
717
718         if (nread != strlen(hello)) {
719                 printf("smb2cli_read returned %d bytes, expected %d\n",
720                        (int)nread, (int)strlen(hello));
721                 return false;
722         }
723
724         if (memcmp(hello, result, nread) != 0) {
725                 printf("smb2cli_read returned '%s', expected '%s'\n",
726                        result, hello);
727                 return false;
728         }
729
730         return true;
731 }
732
733 bool run_smb2_tcon_dependence(int dummy)
734 {
735         struct cli_state *cli;
736         NTSTATUS status;
737         uint64_t fid_persistent, fid_volatile;
738         const char *hello = "Hello, world\n";
739         uint8_t *result;
740         uint32_t nread;
741         struct smbXcli_tcon *tcon2;
742         uint32_t tcon2_id;
743
744         printf("Starting SMB2-TCON-DEPENDENCE\n");
745
746         if (!torture_init_connection(&cli)) {
747                 return false;
748         }
749
750         status = smbXcli_negprot(cli->conn, cli->timeout,
751                                  PROTOCOL_SMB2_02, PROTOCOL_LATEST);
752         if (!NT_STATUS_IS_OK(status)) {
753                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
754                 return false;
755         }
756
757         status = cli_session_setup_creds(cli, torture_creds);
758         if (!NT_STATUS_IS_OK(status)) {
759                 printf("cli_session_setup returned %s\n", nt_errstr(status));
760                 return false;
761         }
762
763         status = cli_tree_connect(cli, share, "?????", NULL);
764         if (!NT_STATUS_IS_OK(status)) {
765                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
766                 return false;
767         }
768
769         status = smb2cli_create(cli->conn, cli->timeout, cli->smb2.session,
770                         cli->smb2.tcon, "tcon_depedence.txt",
771                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
772                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
773                         SEC_STD_ALL | SEC_FILE_ALL, /* desired_access, */
774                         FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
775                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
776                         FILE_CREATE, /* create_disposition, */
777                         FILE_DELETE_ON_CLOSE, /* create_options, */
778                         NULL, /* smb2_create_blobs *blobs */
779                         &fid_persistent,
780                         &fid_volatile,
781                         NULL, NULL, NULL);
782         if (!NT_STATUS_IS_OK(status)) {
783                 printf("smb2cli_create on cli %s\n", nt_errstr(status));
784                 return false;
785         }
786
787         status = smb2cli_write(cli->conn, cli->timeout, cli->smb2.session,
788                                cli->smb2.tcon, strlen(hello), 0, fid_persistent,
789                                fid_volatile, 0, 0, (const uint8_t *)hello, NULL);
790         if (!NT_STATUS_IS_OK(status)) {
791                 printf("smb2cli_write returned %s\n", nt_errstr(status));
792                 return false;
793         }
794
795         status = smb2cli_flush(cli->conn, cli->timeout, cli->smb2.session,
796                                cli->smb2.tcon, fid_persistent, fid_volatile);
797         if (!NT_STATUS_IS_OK(status)) {
798                 printf("smb2cli_flush returned %s\n", nt_errstr(status));
799                 return false;
800         }
801
802         status = smb2cli_read(cli->conn, cli->timeout, cli->smb2.session,
803                               cli->smb2.tcon, 0x10000, 0, fid_persistent,
804                               fid_volatile, 2, 0,
805                               talloc_tos(), &result, &nread);
806         if (!NT_STATUS_IS_OK(status)) {
807                 printf("smb2cli_read returned %s\n", nt_errstr(status));
808                 return false;
809         }
810
811         if (nread != strlen(hello)) {
812                 printf("smb2cli_read returned %d bytes, expected %d\n",
813                        (int)nread, (int)strlen(hello));
814                 return false;
815         }
816
817         if (memcmp(hello, result, nread) != 0) {
818                 printf("smb2cli_read returned '%s', expected '%s'\n",
819                        result, hello);
820                 return false;
821         }
822
823         /* check behaviour with wrong tid... */
824
825         tcon2 = smbXcli_tcon_create(cli);
826         tcon2_id = smb2cli_tcon_current_id(cli->smb2.tcon);
827         tcon2_id++;
828         smb2cli_tcon_set_values(tcon2,
829                                 NULL, /* session */
830                                 tcon2_id,
831                                 0, /* type */
832                                 0, /* flags */
833                                 0, /* capabilities */
834                                 0  /* maximal_access */);
835
836         status = smb2cli_read(cli->conn, cli->timeout, cli->smb2.session,
837                               tcon2, 0x10000, 0, fid_persistent,
838                               fid_volatile, 2, 0,
839                               talloc_tos(), &result, &nread);
840         if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED)) {
841                 printf("smb2cli_read returned %s\n", nt_errstr(status));
842                 return false;
843         }
844
845         talloc_free(tcon2);
846
847         return true;
848 }
849
850 bool run_smb2_multi_channel(int dummy)
851 {
852         struct cli_state *cli1;
853         struct cli_state *cli2;
854         struct cli_state *cli3;
855         NTSTATUS status;
856         bool ok;
857         uint64_t fid_persistent, fid_volatile;
858         struct tevent_context *ev;
859         struct tevent_req *subreq;
860         DATA_BLOB in_blob = data_blob_null;
861         DATA_BLOB out_blob;
862         DATA_BLOB channel_session_key;
863         struct auth_generic_state *auth_generic_state;
864         struct iovec *recv_iov;
865         const char *hello = "Hello, world\n";
866         uint8_t *result;
867         uint32_t nread;
868         struct GUID saved_guid = cli_state_client_guid;
869
870         printf("Starting SMB2-MULTI-CHANNEL\n");
871
872         cli_state_client_guid = GUID_random();
873
874         if (!torture_init_connection(&cli1)) {
875                 return false;
876         }
877
878         if (!torture_init_connection(&cli2)) {
879                 return false;
880         }
881
882         if (!torture_init_connection(&cli3)) {
883                 return false;
884         }
885
886         cli_state_client_guid = saved_guid;
887
888         status = smbXcli_negprot(cli1->conn, cli1->timeout,
889                                  PROTOCOL_SMB3_00, PROTOCOL_LATEST);
890         if (!NT_STATUS_IS_OK(status)) {
891                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
892                 return false;
893         }
894
895         status = smbXcli_negprot(cli2->conn, cli2->timeout,
896                                  PROTOCOL_SMB3_00, PROTOCOL_LATEST);
897         if (!NT_STATUS_IS_OK(status)) {
898                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
899                 return false;
900         }
901
902         status = smbXcli_negprot(cli3->conn, cli3->timeout,
903                                  PROTOCOL_SMB3_00, PROTOCOL_LATEST);
904         if (!NT_STATUS_IS_OK(status)) {
905                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
906                 return false;
907         }
908
909         status = cli_session_setup_creds(cli1, torture_creds);
910         if (!NT_STATUS_IS_OK(status)) {
911                 printf("smb2cli_sesssetup returned %s\n", nt_errstr(status));
912                 return false;
913         }
914
915         status = cli_tree_connect(cli1, share, "?????", NULL);
916         if (!NT_STATUS_IS_OK(status)) {
917                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
918                 return false;
919         }
920
921         status = smb2cli_session_create_channel(cli2,
922                                                 cli1->smb2.session,
923                                                 cli2->conn,
924                                                 &cli2->smb2.session);
925         if (!NT_STATUS_IS_OK(status)) {
926                 printf("smb2cli_session_create_channel returned %s\n",
927                         nt_errstr(status));
928                 return false;
929         }
930
931         status = auth_generic_client_prepare(talloc_tos(), &auth_generic_state);
932         if (!NT_STATUS_IS_OK(status)) {
933                 printf("auth_generic_client_prepare returned %s\n", nt_errstr(status));
934                 return false;
935         }
936
937         gensec_want_feature(auth_generic_state->gensec_security,
938                             GENSEC_FEATURE_SESSION_KEY);
939
940         status = auth_generic_set_creds(auth_generic_state, torture_creds);
941         if (!NT_STATUS_IS_OK(status)) {
942                 printf("auth_generic_set_creds returned %s\n", nt_errstr(status));
943                 return false;
944         }
945
946         status = auth_generic_client_start(auth_generic_state, GENSEC_OID_NTLMSSP);
947         if (!NT_STATUS_IS_OK(status)) {
948                 printf("auth_generic_client_start returned %s\n", nt_errstr(status));
949                 return false;
950         }
951
952         ev = samba_tevent_context_init(talloc_tos());
953         if (ev == NULL) {
954                 printf("samba_tevent_context_init() returned NULL\n");
955                 return false;
956         }
957
958         status = gensec_update(auth_generic_state->gensec_security,
959                                talloc_tos(), data_blob_null, &in_blob);
960         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
961                 printf("gensec_update returned %s\n", nt_errstr(status));
962                 return false;
963         }
964
965         subreq = smb2cli_session_setup_send(talloc_tos(), ev,
966                                             cli2->conn,
967                                             cli2->timeout,
968                                             cli2->smb2.session,
969                                             0x01, /* in_flags */
970                                             SMB2_CAP_DFS, /* in_capabilities */
971                                             0, /* in_channel */
972                                             0, /* in_previous_session_id */
973                                             &in_blob); /* in_security_buffer */
974         if (subreq == NULL) {
975                 printf("smb2cli_session_setup_send() returned NULL\n");
976                 return false;
977         }
978
979         ok = tevent_req_poll(subreq, ev);
980         if (!ok) {
981                 printf("tevent_req_poll() returned false\n");
982                 return false;
983         }
984
985         status = smb2cli_session_setup_recv(subreq, talloc_tos(),
986                                             NULL, &out_blob);
987         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
988                 printf("smb2cli_session_setup_recv returned %s\n",
989                         nt_errstr(status));
990                 return false;
991         }
992
993         status = gensec_update(auth_generic_state->gensec_security,
994                                talloc_tos(), out_blob, &in_blob);
995         if (!NT_STATUS_IS_OK(status)) {
996                 printf("auth_generic_update returned %s\n", nt_errstr(status));
997                 return false;
998         }
999
1000         subreq = smb2cli_session_setup_send(talloc_tos(), ev,
1001                                             cli2->conn,
1002                                             cli2->timeout,
1003                                             cli2->smb2.session,
1004                                             0x01, /* in_flags */
1005                                             SMB2_CAP_DFS, /* in_capabilities */
1006                                             0, /* in_channel */
1007                                             0, /* in_previous_session_id */
1008                                             &in_blob); /* in_security_buffer */
1009         if (subreq == NULL) {
1010                 printf("smb2cli_session_setup_send() returned NULL\n");
1011                 return false;
1012         }
1013
1014         ok = tevent_req_poll(subreq, ev);
1015         if (!ok) {
1016                 printf("tevent_req_poll() returned false\n");
1017                 return false;
1018         }
1019
1020         status = smb2cli_session_setup_recv(subreq, talloc_tos(),
1021                                             &recv_iov, &out_blob);
1022         if (!NT_STATUS_IS_OK(status)) {
1023                 printf("smb2cli_session_setup_recv returned %s\n",
1024                         nt_errstr(status));
1025                 return false;
1026         }
1027
1028         status = gensec_session_key(auth_generic_state->gensec_security, talloc_tos(),
1029                                     &channel_session_key);
1030         if (!NT_STATUS_IS_OK(status)) {
1031                 printf("gensec_session_key returned %s\n",
1032                         nt_errstr(status));
1033                 return false;
1034         }
1035
1036         status = smb2cli_session_set_channel_key(cli2->smb2.session,
1037                                                  channel_session_key,
1038                                                  recv_iov);
1039         if (!NT_STATUS_IS_OK(status)) {
1040                 printf("smb2cli_session_set_channel_key %s\n", nt_errstr(status));
1041                 return false;
1042         }
1043
1044         status = smb2cli_session_create_channel(cli3,
1045                                                 cli1->smb2.session,
1046                                                 cli3->conn,
1047                                                 &cli3->smb2.session);
1048         if (!NT_STATUS_IS_OK(status)) {
1049                 printf("smb2cli_session_create_channel returned %s\n",
1050                         nt_errstr(status));
1051                 return false;
1052         }
1053
1054         status = auth_generic_client_prepare(talloc_tos(), &auth_generic_state);
1055         if (!NT_STATUS_IS_OK(status)) {
1056                 printf("auth_generic_client_prepare returned %s\n", nt_errstr(status));
1057                 return false;
1058         }
1059
1060         gensec_want_feature(auth_generic_state->gensec_security,
1061                             GENSEC_FEATURE_SESSION_KEY);
1062
1063         status = auth_generic_set_creds(auth_generic_state, torture_creds);
1064         if (!NT_STATUS_IS_OK(status)) {
1065                 printf("auth_generic_set_creds returned %s\n", nt_errstr(status));
1066                 return false;
1067         }
1068
1069         status = auth_generic_client_start(auth_generic_state, GENSEC_OID_NTLMSSP);
1070         if (!NT_STATUS_IS_OK(status)) {
1071                 printf("auth_generic_client_start returned %s\n", nt_errstr(status));
1072                 return false;
1073         }
1074
1075         status = gensec_update(auth_generic_state->gensec_security,
1076                                talloc_tos(), data_blob_null, &in_blob);
1077         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1078                 printf("gensec_update returned %s\n", nt_errstr(status));
1079                 return false;
1080         }
1081
1082         subreq = smb2cli_session_setup_send(talloc_tos(), ev,
1083                                             cli3->conn,
1084                                             cli3->timeout,
1085                                             cli3->smb2.session,
1086                                             0x01, /* in_flags */
1087                                             SMB2_CAP_DFS, /* in_capabilities */
1088                                             0, /* in_channel */
1089                                             0, /* in_previous_session_id */
1090                                             &in_blob); /* in_security_buffer */
1091         if (subreq == NULL) {
1092                 printf("smb2cli_session_setup_send() returned NULL\n");
1093                 return false;
1094         }
1095
1096         ok = tevent_req_poll(subreq, ev);
1097         if (!ok) {
1098                 printf("tevent_req_poll() returned false\n");
1099                 return false;
1100         }
1101
1102         status = smb2cli_session_setup_recv(subreq, talloc_tos(),
1103                                             NULL, &out_blob);
1104         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1105                 printf("smb2cli_session_setup_recv returned %s\n",
1106                         nt_errstr(status));
1107                 return false;
1108         }
1109
1110         status = gensec_update(auth_generic_state->gensec_security,
1111                                talloc_tos(), out_blob, &in_blob);
1112         if (!NT_STATUS_IS_OK(status)) {
1113                 printf("auth_generic_update returned %s\n", nt_errstr(status));
1114                 return false;
1115         }
1116
1117         subreq = smb2cli_session_setup_send(talloc_tos(), ev,
1118                                             cli3->conn,
1119                                             cli3->timeout,
1120                                             cli3->smb2.session,
1121                                             0x01, /* in_flags */
1122                                             SMB2_CAP_DFS, /* in_capabilities */
1123                                             0, /* in_channel */
1124                                             0, /* in_previous_session_id */
1125                                             &in_blob); /* in_security_buffer */
1126         if (subreq == NULL) {
1127                 printf("smb2cli_session_setup_send() returned NULL\n");
1128                 return false;
1129         }
1130
1131         ok = tevent_req_poll(subreq, ev);
1132         if (!ok) {
1133                 printf("tevent_req_poll() returned false\n");
1134                 return false;
1135         }
1136
1137         status = smb2cli_session_setup_recv(subreq, talloc_tos(),
1138                                             &recv_iov, &out_blob);
1139         if (!NT_STATUS_IS_OK(status)) {
1140                 printf("smb2cli_session_setup_recv returned %s\n",
1141                         nt_errstr(status));
1142                 return false;
1143         }
1144
1145         status = gensec_session_key(auth_generic_state->gensec_security, talloc_tos(),
1146                                     &channel_session_key);
1147         if (!NT_STATUS_IS_OK(status)) {
1148                 printf("gensec_session_key returned %s\n",
1149                         nt_errstr(status));
1150                 return false;
1151         }
1152
1153         status = smb2cli_session_set_channel_key(cli3->smb2.session,
1154                                                  channel_session_key,
1155                                                  recv_iov);
1156         if (!NT_STATUS_IS_OK(status)) {
1157                 printf("smb2cli_session_set_channel_key %s\n", nt_errstr(status));
1158                 return false;
1159         }
1160
1161         status = smb2cli_create(cli2->conn, cli2->timeout, cli2->smb2.session,
1162                         cli1->smb2.tcon, "multi-channel.txt",
1163                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
1164                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
1165                         SEC_STD_ALL | SEC_FILE_ALL, /* desired_access, */
1166                         FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
1167                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
1168                         FILE_CREATE, /* create_disposition, */
1169                         FILE_DELETE_ON_CLOSE, /* create_options, */
1170                         NULL, /* smb2_create_blobs *blobs */
1171                         &fid_persistent,
1172                         &fid_volatile,
1173                         NULL, NULL, NULL);
1174         if (!NT_STATUS_IS_OK(status)) {
1175                 printf("smb2cli_create on cli2 %s\n", nt_errstr(status));
1176                 return false;
1177         }
1178
1179         status = smb2cli_write(cli1->conn, cli1->timeout, cli1->smb2.session,
1180                                cli1->smb2.tcon, strlen(hello), 0, fid_persistent,
1181                                fid_volatile, 0, 0, (const uint8_t *)hello, NULL);
1182         if (!NT_STATUS_IS_OK(status)) {
1183                 printf("smb2cli_write returned %s\n", nt_errstr(status));
1184                 return false;
1185         }
1186
1187         status = smb2cli_flush(cli2->conn, cli2->timeout, cli2->smb2.session,
1188                                cli1->smb2.tcon, fid_persistent, fid_volatile);
1189         if (!NT_STATUS_IS_OK(status)) {
1190                 printf("smb2cli_flush returned %s\n", nt_errstr(status));
1191                 return false;
1192         }
1193
1194         status = smb2cli_flush(cli1->conn, cli1->timeout, cli1->smb2.session,
1195                                cli1->smb2.tcon, fid_persistent, fid_volatile);
1196         if (!NT_STATUS_IS_OK(status)) {
1197                 printf("smb2cli_flush returned %s\n", nt_errstr(status));
1198                 return false;
1199         }
1200
1201         status = smb2cli_flush(cli3->conn, cli3->timeout, cli3->smb2.session,
1202                                cli1->smb2.tcon, fid_persistent, fid_volatile);
1203         if (!NT_STATUS_IS_OK(status)) {
1204                 printf("smb2cli_flush returned %s\n", nt_errstr(status));
1205                 return false;
1206         }
1207
1208         status = smb2cli_read(cli2->conn, cli2->timeout, cli2->smb2.session,
1209                               cli1->smb2.tcon, 0x10000, 0, fid_persistent,
1210                               fid_volatile, 2, 0,
1211                               talloc_tos(), &result, &nread);
1212         if (!NT_STATUS_IS_OK(status)) {
1213                 printf("smb2cli_read returned %s\n", nt_errstr(status));
1214                 return false;
1215         }
1216
1217         if (nread != strlen(hello)) {
1218                 printf("smb2cli_read returned %d bytes, expected %d\n",
1219                        (int)nread, (int)strlen(hello));
1220                 return false;
1221         }
1222
1223         if (memcmp(hello, result, nread) != 0) {
1224                 printf("smb2cli_read returned '%s', expected '%s'\n",
1225                        result, hello);
1226                 return false;
1227         }
1228
1229         status = auth_generic_client_prepare(talloc_tos(), &auth_generic_state);
1230         if (!NT_STATUS_IS_OK(status)) {
1231                 printf("auth_generic_client_prepare returned %s\n", nt_errstr(status));
1232                 return false;
1233         }
1234
1235         gensec_want_feature(auth_generic_state->gensec_security,
1236                             GENSEC_FEATURE_SESSION_KEY);
1237
1238         status = auth_generic_set_creds(auth_generic_state, torture_creds);
1239         if (!NT_STATUS_IS_OK(status)) {
1240                 printf("auth_generic_set_creds returned %s\n", nt_errstr(status));
1241                 return false;
1242         }
1243
1244         status = auth_generic_client_start(auth_generic_state, GENSEC_OID_NTLMSSP);
1245         if (!NT_STATUS_IS_OK(status)) {
1246                 printf("auth_generic_client_start returned %s\n", nt_errstr(status));
1247                 return false;
1248         }
1249
1250         status = gensec_update(auth_generic_state->gensec_security,
1251                                talloc_tos(), data_blob_null, &in_blob);
1252         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1253                 printf("gensec_update returned %s\n", nt_errstr(status));
1254                 return false;
1255         }
1256
1257         subreq = smb2cli_session_setup_send(talloc_tos(), ev,
1258                                             cli3->conn,
1259                                             cli3->timeout,
1260                                             cli3->smb2.session,
1261                                             0x0, /* in_flags */
1262                                             SMB2_CAP_DFS, /* in_capabilities */
1263                                             0, /* in_channel */
1264                                             0, /* in_previous_session_id */
1265                                             &in_blob); /* in_security_buffer */
1266         if (subreq == NULL) {
1267                 printf("smb2cli_session_setup_send() returned NULL\n");
1268                 return false;
1269         }
1270
1271         ok = tevent_req_poll(subreq, ev);
1272         if (!ok) {
1273                 printf("tevent_req_poll() returned false\n");
1274                 return false;
1275         }
1276
1277         status = smb2cli_session_setup_recv(subreq, talloc_tos(),
1278                                             NULL, &out_blob);
1279         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1280                 printf("smb2cli_session_setup_recv returned %s\n",
1281                         nt_errstr(status));
1282                 return false;
1283         }
1284
1285         status = gensec_update(auth_generic_state->gensec_security,
1286                                talloc_tos(), out_blob, &in_blob);
1287         if (!NT_STATUS_IS_OK(status)) {
1288                 printf("auth_generic_update returned %s\n", nt_errstr(status));
1289                 return false;
1290         }
1291
1292         status = smb2cli_flush(cli1->conn, cli1->timeout, cli1->smb2.session,
1293                                cli1->smb2.tcon, fid_persistent, fid_volatile);
1294         if (!NT_STATUS_IS_OK(status)) {
1295                 printf("smb2cli_flush returned %s\n", nt_errstr(status));
1296                 return false;
1297         }
1298
1299         status = smb2cli_flush(cli2->conn, cli2->timeout, cli2->smb2.session,
1300                                cli1->smb2.tcon, fid_persistent, fid_volatile);
1301         if (!NT_STATUS_IS_OK(status)) {
1302                 printf("smb2cli_flush returned %s\n", nt_errstr(status));
1303                 return false;
1304         }
1305
1306         status = smb2cli_flush(cli3->conn, cli3->timeout, cli3->smb2.session,
1307                                cli1->smb2.tcon, fid_persistent, fid_volatile);
1308         if (!NT_STATUS_IS_OK(status)) {
1309                 printf("smb2cli_flush returned %s\n", nt_errstr(status));
1310                 return false;
1311         }
1312
1313         status = smb2cli_create(cli1->conn, cli1->timeout, cli1->smb2.session,
1314                         cli1->smb2.tcon, "multi-channel-invalid.txt",
1315                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
1316                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
1317                         SEC_STD_ALL | SEC_FILE_ALL, /* desired_access, */
1318                         FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
1319                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
1320                         FILE_CREATE, /* create_disposition, */
1321                         FILE_DELETE_ON_CLOSE, /* create_options, */
1322                         NULL, /* smb2_create_blobs *blobs */
1323                         &fid_persistent,
1324                         &fid_volatile,
1325                         NULL, NULL, NULL);
1326         if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
1327                 printf("smb2cli_create %s\n", nt_errstr(status));
1328                 return false;
1329         }
1330
1331         status = smb2cli_create(cli2->conn, cli2->timeout, cli2->smb2.session,
1332                         cli1->smb2.tcon, "multi-channel-invalid.txt",
1333                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
1334                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
1335                         SEC_STD_ALL | SEC_FILE_ALL, /* desired_access, */
1336                         FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
1337                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
1338                         FILE_CREATE, /* create_disposition, */
1339                         FILE_DELETE_ON_CLOSE, /* create_options, */
1340                         NULL, /* smb2_create_blobs *blobs */
1341                         &fid_persistent,
1342                         &fid_volatile,
1343                         NULL, NULL, NULL);
1344         if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
1345                 printf("smb2cli_create %s\n", nt_errstr(status));
1346                 return false;
1347         }
1348
1349         status = smb2cli_create(cli3->conn, cli3->timeout, cli3->smb2.session,
1350                         cli1->smb2.tcon, "multi-channel-invalid.txt",
1351                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
1352                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
1353                         SEC_STD_ALL | SEC_FILE_ALL, /* desired_access, */
1354                         FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
1355                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
1356                         FILE_CREATE, /* create_disposition, */
1357                         FILE_DELETE_ON_CLOSE, /* create_options, */
1358                         NULL, /* smb2_create_blobs *blobs */
1359                         &fid_persistent,
1360                         &fid_volatile,
1361                         NULL, NULL, NULL);
1362         if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
1363                 printf("smb2cli_create %s\n", nt_errstr(status));
1364                 return false;
1365         }
1366
1367         subreq = smb2cli_session_setup_send(talloc_tos(), ev,
1368                                             cli2->conn,
1369                                             cli2->timeout,
1370                                             cli2->smb2.session,
1371                                             0x0, /* in_flags */
1372                                             SMB2_CAP_DFS, /* in_capabilities */
1373                                             0, /* in_channel */
1374                                             0, /* in_previous_session_id */
1375                                             &in_blob); /* in_security_buffer */
1376         if (subreq == NULL) {
1377                 printf("smb2cli_session_setup_send() returned NULL\n");
1378                 return false;
1379         }
1380
1381         ok = tevent_req_poll(subreq, ev);
1382         if (!ok) {
1383                 printf("tevent_req_poll() returned false\n");
1384                 return false;
1385         }
1386
1387         status = smb2cli_session_setup_recv(subreq, talloc_tos(),
1388                                             &recv_iov, &out_blob);
1389         if (!NT_STATUS_IS_OK(status)) {
1390                 printf("smb2cli_session_setup_recv returned %s\n",
1391                         nt_errstr(status));
1392                 return false;
1393         }
1394
1395         status = smb2cli_close(cli3->conn, cli3->timeout, cli3->smb2.session,
1396                                cli1->smb2.tcon, 0, fid_persistent, fid_volatile);
1397         if (!NT_STATUS_IS_OK(status)) {
1398                 printf("smb2cli_close returned %s\n", nt_errstr(status));
1399                 return false;
1400         }
1401
1402         status = smb2cli_flush(cli3->conn, cli3->timeout, cli3->smb2.session,
1403                                cli1->smb2.tcon, fid_persistent, fid_volatile);
1404         if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED)) {
1405                 printf("smb2cli_flush returned %s\n", nt_errstr(status));
1406                 return false;
1407         }
1408
1409         status = smb2cli_flush(cli2->conn, cli2->timeout, cli2->smb2.session,
1410                                cli1->smb2.tcon, fid_persistent, fid_volatile);
1411         if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED)) {
1412                 printf("smb2cli_flush returned %s\n", nt_errstr(status));
1413                 return false;
1414         }
1415
1416         status = smb2cli_flush(cli1->conn, cli1->timeout, cli1->smb2.session,
1417                                cli1->smb2.tcon, fid_persistent, fid_volatile);
1418         if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED)) {
1419                 printf("smb2cli_flush returned %s\n", nt_errstr(status));
1420                 return false;
1421         }
1422
1423         return true;
1424 }
1425
1426 bool run_smb2_session_reauth(int dummy)
1427 {
1428         struct cli_state *cli;
1429         NTSTATUS status;
1430         bool ok;
1431         uint64_t fid_persistent, fid_volatile;
1432         uint64_t dir_persistent, dir_volatile;
1433         uint8_t *dir_data;
1434         uint32_t dir_data_length;
1435         struct tevent_context *ev;
1436         struct tevent_req *subreq;
1437         DATA_BLOB in_blob = data_blob_null;
1438         DATA_BLOB out_blob;
1439         DATA_BLOB in_input_buffer;
1440         DATA_BLOB out_output_buffer;
1441         uint8_t in_file_info_class;
1442         struct auth_generic_state *auth_generic_state;
1443         struct iovec *recv_iov;
1444         uint32_t saved_tid;
1445         struct smbXcli_tcon *saved_tcon;
1446
1447         printf("Starting SMB2-SESSION_REAUTH\n");
1448
1449         if (!torture_init_connection(&cli)) {
1450                 return false;
1451         }
1452
1453         /*
1454          * PROTOCOL_SMB2_22 has a bug in win8pre0
1455          * it behaves like PROTOCOL_SMB2_02
1456          * and returns NT_STATUS_REQUEST_NOT_ACCEPTED,
1457          * while it allows it on PROTOCOL_SMB2_10.
1458          */
1459         status = smbXcli_negprot(cli->conn, cli->timeout,
1460                                  PROTOCOL_SMB2_10, PROTOCOL_SMB2_10);
1461         if (!NT_STATUS_IS_OK(status)) {
1462                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
1463                 return false;
1464         }
1465
1466         status = cli_session_setup_creds(cli, torture_creds);
1467         if (!NT_STATUS_IS_OK(status)) {
1468                 printf("smb2cli_sesssetup returned %s\n", nt_errstr(status));
1469                 return false;
1470         }
1471
1472         status = cli_tree_connect(cli, share, "?????", NULL);
1473         if (!NT_STATUS_IS_OK(status)) {
1474                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
1475                 return false;
1476         }
1477
1478         status = smb2cli_create(cli->conn, cli->timeout, cli->smb2.session,
1479                         cli->smb2.tcon, "session-reauth.txt",
1480                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
1481                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
1482                         SEC_STD_ALL | SEC_FILE_ALL, /* desired_access, */
1483                         FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
1484                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
1485                         FILE_CREATE, /* create_disposition, */
1486                         FILE_DELETE_ON_CLOSE, /* create_options, */
1487                         NULL, /* smb2_create_blobs *blobs */
1488                         &fid_persistent,
1489                         &fid_volatile,
1490                         NULL, NULL, NULL);
1491         if (!NT_STATUS_IS_OK(status)) {
1492                 printf("smb2cli_create %s\n", nt_errstr(status));
1493                 return false;
1494         }
1495
1496         status = smb2cli_create(cli->conn, cli->timeout, cli->smb2.session,
1497                         cli->smb2.tcon, "",
1498                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
1499                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
1500                         SEC_STD_SYNCHRONIZE|
1501                         SEC_DIR_LIST|
1502                         SEC_DIR_READ_ATTRIBUTE, /* desired_access, */
1503                         0, /* file_attributes, */
1504                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
1505                         FILE_OPEN, /* create_disposition, */
1506                         FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE, /* create_options, */
1507                         NULL, /* smb2_create_blobs *blobs */
1508                         &dir_persistent,
1509                         &dir_volatile,
1510                         NULL, NULL, NULL);
1511         if (!NT_STATUS_IS_OK(status)) {
1512                 printf("smb2cli_create returned %s\n", nt_errstr(status));
1513                 return false;
1514         }
1515
1516         status = smb2cli_query_directory(
1517                 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
1518                 1, 0x3, 0, dir_persistent, dir_volatile,
1519                 "session-reauth.txt", 0xffff,
1520                 talloc_tos(), &dir_data, &dir_data_length);
1521         if (!NT_STATUS_IS_OK(status)) {
1522                 printf("smb2cli_query_directory returned %s\n", nt_errstr(status));
1523                 return false;
1524         }
1525
1526         status = auth_generic_client_prepare(talloc_tos(), &auth_generic_state);
1527         if (!NT_STATUS_IS_OK(status)) {
1528                 printf("auth_generic_client_prepare returned %s\n", nt_errstr(status));
1529                 return false;
1530         }
1531
1532         gensec_want_feature(auth_generic_state->gensec_security,
1533                             GENSEC_FEATURE_SESSION_KEY);
1534
1535         status = auth_generic_set_creds(auth_generic_state, torture_creds);
1536         if (!NT_STATUS_IS_OK(status)) {
1537                 printf("auth_generic_set_creds returned %s\n", nt_errstr(status));
1538                 return false;
1539         }
1540
1541         status = auth_generic_client_start(auth_generic_state, GENSEC_OID_NTLMSSP);
1542         if (!NT_STATUS_IS_OK(status)) {
1543                 printf("auth_generic_client_start returned %s\n", nt_errstr(status));
1544                 return false;
1545         }
1546
1547         ev = samba_tevent_context_init(talloc_tos());
1548         if (ev == NULL) {
1549                 printf("samba_tevent_context_init() returned NULL\n");
1550                 return false;
1551         }
1552
1553         status = gensec_update(auth_generic_state->gensec_security,
1554                                talloc_tos(), data_blob_null, &in_blob);
1555         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1556                 printf("gensec_update returned %s\n", nt_errstr(status));
1557                 return false;
1558         }
1559
1560         subreq = smb2cli_session_setup_send(talloc_tos(), ev,
1561                                             cli->conn,
1562                                             cli->timeout,
1563                                             cli->smb2.session,
1564                                             0x0, /* in_flags */
1565                                             SMB2_CAP_DFS, /* in_capabilities */
1566                                             0, /* in_channel */
1567                                             0, /* in_previous_session_id */
1568                                             &in_blob); /* in_security_buffer */
1569         if (subreq == NULL) {
1570                 printf("smb2cli_session_setup_send() returned NULL\n");
1571                 return false;
1572         }
1573
1574         ok = tevent_req_poll(subreq, ev);
1575         if (!ok) {
1576                 printf("tevent_req_poll() returned false\n");
1577                 return false;
1578         }
1579
1580         status = smb2cli_session_setup_recv(subreq, talloc_tos(),
1581                                             NULL, &out_blob);
1582         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1583                 printf("smb2cli_session_setup_recv returned %s\n",
1584                         nt_errstr(status));
1585                 return false;
1586         }
1587
1588         status = gensec_update(auth_generic_state->gensec_security,
1589                                talloc_tos(), out_blob, &in_blob);
1590         if (!NT_STATUS_IS_OK(status)) {
1591                 printf("auth_generic_update returned %s\n", nt_errstr(status));
1592                 return false;
1593         }
1594
1595         status = smb2cli_flush(cli->conn, cli->timeout, cli->smb2.session,
1596                                cli->smb2.tcon, fid_persistent, fid_volatile);
1597         if (!NT_STATUS_IS_OK(status)) {
1598                 printf("smb2cli_flush returned %s\n", nt_errstr(status));
1599                 return false;
1600         }
1601
1602         status = smb2cli_query_directory(
1603                 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
1604                 1, 0x3, 0, dir_persistent, dir_volatile,
1605                 "session-reauth.txt", 0xffff,
1606                 talloc_tos(), &dir_data, &dir_data_length);
1607         if (!NT_STATUS_IS_OK(status)) {
1608                 printf("smb2cli_query_directory returned %s\n", nt_errstr(status));
1609                 return false;
1610         }
1611
1612         /*
1613          * query_info seems to be a path based operation on Windows...
1614          */
1615         status = smb2cli_query_info(cli->conn,
1616                                     cli->timeout,
1617                                     cli->smb2.session,
1618                                     cli->smb2.tcon,
1619                                     SMB2_0_INFO_SECURITY,
1620                                     0, /* in_file_info_class */
1621                                     1024, /* in_max_output_length */
1622                                     NULL, /* in_input_buffer */
1623                                     SECINFO_OWNER, /* in_additional_info */
1624                                     0, /* in_flags */
1625                                     fid_persistent,
1626                                     fid_volatile,
1627                                     talloc_tos(),
1628                                     &out_output_buffer);
1629         if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
1630                 printf("smb2cli_query_info (security) returned %s\n", nt_errstr(status));
1631                 return false;
1632         }
1633
1634         in_file_info_class = SMB_FILE_POSITION_INFORMATION - 1000;
1635         status = smb2cli_query_info(cli->conn,
1636                                     cli->timeout,
1637                                     cli->smb2.session,
1638                                     cli->smb2.tcon,
1639                                     SMB2_0_INFO_FILE,
1640                                     in_file_info_class,
1641                                     1024, /* in_max_output_length */
1642                                     NULL, /* in_input_buffer */
1643                                     0, /* in_additional_info */
1644                                     0, /* in_flags */
1645                                     fid_persistent,
1646                                     fid_volatile,
1647                                     talloc_tos(),
1648                                     &out_output_buffer);
1649         if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
1650                 printf("smb2cli_query_info (position) returned %s\n", nt_errstr(status));
1651                 return false;
1652         }
1653
1654         in_input_buffer = data_blob_talloc(talloc_tos(), NULL, 8);
1655         SBVAL(in_input_buffer.data, 0, 512);
1656
1657         in_file_info_class = SMB_FILE_POSITION_INFORMATION - 1000;
1658         status = smb2cli_set_info(cli->conn,
1659                                   cli->timeout,
1660                                   cli->smb2.session,
1661                                   cli->smb2.tcon,
1662                                   SMB2_0_INFO_FILE,
1663                                   in_file_info_class,
1664                                   &in_input_buffer,
1665                                   0, /* in_additional_info */
1666                                   fid_persistent,
1667                                   fid_volatile);
1668         if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
1669                 printf("smb2cli_set_info (position) returned %s\n", nt_errstr(status));
1670                 return false;
1671         }
1672
1673         status = smb2cli_create(cli->conn, cli->timeout, cli->smb2.session,
1674                         cli->smb2.tcon, "session-reauth-invalid.txt",
1675                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
1676                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
1677                         SEC_STD_ALL | SEC_FILE_ALL, /* desired_access, */
1678                         FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
1679                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
1680                         FILE_CREATE, /* create_disposition, */
1681                         FILE_DELETE_ON_CLOSE, /* create_options, */
1682                         NULL, /* smb2_create_blobs *blobs */
1683                         &fid_persistent,
1684                         &fid_volatile,
1685                         NULL, NULL, NULL);
1686         if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
1687                 printf("smb2cli_create %s\n", nt_errstr(status));
1688                 return false;
1689         }
1690
1691         status = smb2cli_create(cli->conn, cli->timeout, cli->smb2.session,
1692                         cli->smb2.tcon, "",
1693                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
1694                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
1695                         SEC_STD_SYNCHRONIZE|
1696                         SEC_DIR_LIST|
1697                         SEC_DIR_READ_ATTRIBUTE, /* desired_access, */
1698                         0, /* file_attributes, */
1699                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
1700                         FILE_OPEN, /* create_disposition, */
1701                         FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE, /* create_options, */
1702                         NULL, /* smb2_create_blobs *blobs */
1703                         &dir_persistent,
1704                         &dir_volatile,
1705                         NULL, NULL, NULL);
1706         if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
1707                 printf("smb2cli_create returned %s\n", nt_errstr(status));
1708                 return false;
1709         }
1710
1711         saved_tid = smb2cli_tcon_current_id(cli->smb2.tcon);
1712         saved_tcon = cli->smb2.tcon;
1713         cli->smb2.tcon = smbXcli_tcon_create(cli);
1714         smb2cli_tcon_set_values(cli->smb2.tcon,
1715                                 NULL, /* session */
1716                                 saved_tid,
1717                                 0, /* type */
1718                                 0, /* flags */
1719                                 0, /* capabilities */
1720                                 0  /* maximal_access */);
1721         status = cli_tree_connect(cli, share, "?????", NULL);
1722         if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
1723                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
1724                 return false;
1725         }
1726         talloc_free(cli->smb2.tcon);
1727         cli->smb2.tcon = saved_tcon;
1728
1729         subreq = smb2cli_session_setup_send(talloc_tos(), ev,
1730                                             cli->conn,
1731                                             cli->timeout,
1732                                             cli->smb2.session,
1733                                             0x0, /* in_flags */
1734                                             SMB2_CAP_DFS, /* in_capabilities */
1735                                             0, /* in_channel */
1736                                             0, /* in_previous_session_id */
1737                                             &in_blob); /* in_security_buffer */
1738         if (subreq == NULL) {
1739                 printf("smb2cli_session_setup_send() returned NULL\n");
1740                 return false;
1741         }
1742
1743         ok = tevent_req_poll(subreq, ev);
1744         if (!ok) {
1745                 printf("tevent_req_poll() returned false\n");
1746                 return false;
1747         }
1748
1749         status = smb2cli_session_setup_recv(subreq, talloc_tos(),
1750                                             &recv_iov, &out_blob);
1751         if (!NT_STATUS_IS_OK(status)) {
1752                 printf("smb2cli_session_setup_recv returned %s\n",
1753                         nt_errstr(status));
1754                 return false;
1755         }
1756
1757         status = smb2cli_flush(cli->conn, cli->timeout, cli->smb2.session,
1758                                cli->smb2.tcon, fid_persistent, fid_volatile);
1759         if (!NT_STATUS_IS_OK(status)) {
1760                 printf("smb2cli_flush returned %s\n", nt_errstr(status));
1761                 return false;
1762         }
1763
1764         status = smb2cli_query_info(cli->conn,
1765                                     cli->timeout,
1766                                     cli->smb2.session,
1767                                     cli->smb2.tcon,
1768                                     SMB2_0_INFO_SECURITY,
1769                                     0, /* in_file_info_class */
1770                                     1024, /* in_max_output_length */
1771                                     NULL, /* in_input_buffer */
1772                                     SECINFO_OWNER, /* in_additional_info */
1773                                     0, /* in_flags */
1774                                     fid_persistent,
1775                                     fid_volatile,
1776                                     talloc_tos(),
1777                                     &out_output_buffer);
1778         if (!NT_STATUS_IS_OK(status)) {
1779                 printf("smb2cli_query_info (security) returned %s\n", nt_errstr(status));
1780                 return false;
1781         }
1782
1783         in_file_info_class = SMB_FILE_POSITION_INFORMATION - 1000;
1784         status = smb2cli_query_info(cli->conn,
1785                                     cli->timeout,
1786                                     cli->smb2.session,
1787                                     cli->smb2.tcon,
1788                                     SMB2_0_INFO_FILE,
1789                                     in_file_info_class,
1790                                     1024, /* in_max_output_length */
1791                                     NULL, /* in_input_buffer */
1792                                     0, /* in_additional_info */
1793                                     0, /* in_flags */
1794                                     fid_persistent,
1795                                     fid_volatile,
1796                                     talloc_tos(),
1797                                     &out_output_buffer);
1798         if (!NT_STATUS_IS_OK(status)) {
1799                 printf("smb2cli_query_info (position) returned %s\n", nt_errstr(status));
1800                 return false;
1801         }
1802
1803         in_input_buffer = data_blob_talloc(talloc_tos(), NULL, 8);
1804         SBVAL(in_input_buffer.data, 0, 512);
1805
1806         in_file_info_class = SMB_FILE_POSITION_INFORMATION - 1000;
1807         status = smb2cli_set_info(cli->conn,
1808                                   cli->timeout,
1809                                   cli->smb2.session,
1810                                   cli->smb2.tcon,
1811                                   SMB2_0_INFO_FILE,
1812                                   in_file_info_class,
1813                                   &in_input_buffer,
1814                                   0, /* in_additional_info */
1815                                   fid_persistent,
1816                                   fid_volatile);
1817         if (!NT_STATUS_IS_OK(status)) {
1818                 printf("smb2cli_set_info (position) returned %s\n", nt_errstr(status));
1819                 return false;
1820         }
1821
1822         in_file_info_class = SMB_FILE_POSITION_INFORMATION - 1000;
1823         status = smb2cli_query_info(cli->conn,
1824                                     cli->timeout,
1825                                     cli->smb2.session,
1826                                     cli->smb2.tcon,
1827                                     SMB2_0_INFO_FILE,
1828                                     in_file_info_class,
1829                                     1024, /* in_max_output_length */
1830                                     NULL, /* in_input_buffer */
1831                                     0, /* in_additional_info */
1832                                     0, /* in_flags */
1833                                     fid_persistent,
1834                                     fid_volatile,
1835                                     talloc_tos(),
1836                                     &out_output_buffer);
1837         if (!NT_STATUS_IS_OK(status)) {
1838                 printf("smb2cli_query_info (position) returned %s\n", nt_errstr(status));
1839                 return false;
1840         }
1841
1842         status = smb2cli_close(cli->conn, cli->timeout, cli->smb2.session,
1843                                cli->smb2.tcon, 0, fid_persistent, fid_volatile);
1844         if (!NT_STATUS_IS_OK(status)) {
1845                 printf("smb2cli_close returned %s\n", nt_errstr(status));
1846                 return false;
1847         }
1848
1849         status = smb2cli_create(cli->conn, cli->timeout, cli->smb2.session,
1850                         cli->smb2.tcon, "session-reauth.txt",
1851                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
1852                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
1853                         SEC_STD_ALL | SEC_FILE_ALL, /* desired_access, */
1854                         FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
1855                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
1856                         FILE_CREATE, /* create_disposition, */
1857                         FILE_DELETE_ON_CLOSE, /* create_options, */
1858                         NULL, /* smb2_create_blobs *blobs */
1859                         &fid_persistent,
1860                         &fid_volatile,
1861                         NULL, NULL, NULL);
1862         if (!NT_STATUS_IS_OK(status)) {
1863                 printf("smb2cli_create %s\n", nt_errstr(status));
1864                 return false;
1865         }
1866
1867         status = smb2cli_query_directory(
1868                 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
1869                 1, 0x3, 0, dir_persistent, dir_volatile,
1870                 "session-reauth.txt", 0xffff,
1871                 talloc_tos(), &dir_data, &dir_data_length);
1872         if (!NT_STATUS_IS_OK(status)) {
1873                 printf("smb2cli_query_directory returned %s\n", nt_errstr(status));
1874                 return false;
1875         }
1876
1877         status = smb2cli_close(cli->conn, cli->timeout, cli->smb2.session,
1878                                cli->smb2.tcon, 0, dir_persistent, dir_volatile);
1879         if (!NT_STATUS_IS_OK(status)) {
1880                 printf("smb2cli_close returned %s\n", nt_errstr(status));
1881                 return false;
1882         }
1883
1884         status = smb2cli_close(cli->conn, cli->timeout, cli->smb2.session,
1885                                cli->smb2.tcon, 0, fid_persistent, fid_volatile);
1886         if (!NT_STATUS_IS_OK(status)) {
1887                 printf("smb2cli_close returned %s\n", nt_errstr(status));
1888                 return false;
1889         }
1890
1891         saved_tid = smb2cli_tcon_current_id(cli->smb2.tcon);
1892         saved_tcon = cli->smb2.tcon;
1893         cli->smb2.tcon = smbXcli_tcon_create(cli);
1894         smb2cli_tcon_set_values(cli->smb2.tcon,
1895                                 NULL, /* session */
1896                                 saved_tid,
1897                                 0, /* type */
1898                                 0, /* flags */
1899                                 0, /* capabilities */
1900                                 0  /* maximal_access */);
1901         status = cli_tree_connect(cli, share, "?????", NULL);
1902         if (!NT_STATUS_IS_OK(status)) {
1903                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
1904                 return false;
1905         }
1906         talloc_free(cli->smb2.tcon);
1907         cli->smb2.tcon = saved_tcon;
1908
1909         return true;
1910 }
1911
1912 static NTSTATUS check_size(struct cli_state *cli,
1913                                 uint16_t fnum,
1914                                 const char *fname,
1915                                 size_t size)
1916 {
1917         off_t size_read = 0;
1918
1919         NTSTATUS status = cli_qfileinfo_basic(cli,
1920                                 fnum,
1921                                 NULL,
1922                                 &size_read,
1923                                 NULL,
1924                                 NULL,
1925                                 NULL,
1926                                 NULL,
1927                                 NULL);
1928
1929         if (!NT_STATUS_IS_OK(status)) {
1930                 printf("cli_qfileinfo_basic of %s failed (%s)\n",
1931                         fname,
1932                         nt_errstr(status));
1933                 return status;
1934         }
1935
1936         if (size != size_read) {
1937                 printf("size (%u) != size_read(%u) for %s\n",
1938                         (unsigned int)size,
1939                         (unsigned int)size_read,
1940                         fname);
1941                 /* Use EOF to mean bad size. */
1942                 return NT_STATUS_END_OF_FILE;
1943         }
1944         return NT_STATUS_OK;
1945 }
1946
1947 /* Ensure cli_ftruncate() works for SMB2. */
1948
1949 bool run_smb2_ftruncate(int dummy)
1950 {
1951         struct cli_state *cli = NULL;
1952         const char *fname = "smb2_ftruncate.txt";
1953         uint16_t fnum = (uint16_t)-1;
1954         bool correct = false;
1955         size_t buflen = 1024*1024;
1956         uint8_t *buf = NULL;
1957         unsigned int i;
1958         NTSTATUS status;
1959
1960         printf("Starting SMB2-FTRUNCATE\n");
1961
1962         if (!torture_init_connection(&cli)) {
1963                 goto fail;
1964         }
1965
1966         status = smbXcli_negprot(cli->conn, cli->timeout,
1967                                  PROTOCOL_SMB2_02, PROTOCOL_SMB2_02);
1968         if (!NT_STATUS_IS_OK(status)) {
1969                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
1970                 goto fail;
1971         }
1972
1973         status = cli_session_setup_creds(cli, torture_creds);
1974         if (!NT_STATUS_IS_OK(status)) {
1975                 printf("cli_session_setup returned %s\n", nt_errstr(status));
1976                 goto fail;
1977         }
1978
1979         status = cli_tree_connect(cli, share, "?????", NULL);
1980         if (!NT_STATUS_IS_OK(status)) {
1981                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
1982                 goto fail;
1983         }
1984
1985         cli_setatr(cli, fname, 0, 0);
1986         cli_unlink(cli, fname, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
1987
1988         status = cli_ntcreate(cli,
1989                                 fname,
1990                                 0,
1991                                 GENERIC_ALL_ACCESS,
1992                                 FILE_ATTRIBUTE_NORMAL,
1993                                 FILE_SHARE_NONE,
1994                                 FILE_CREATE,
1995                                 0,
1996                                 0,
1997                                 &fnum,
1998                                 NULL);
1999
2000         if (!NT_STATUS_IS_OK(status)) {
2001                 printf("open of %s failed (%s)\n", fname, nt_errstr(status));
2002                 goto fail;
2003         }
2004
2005         buf = talloc_zero_array(cli, uint8_t, buflen);
2006         if (buf == NULL) {
2007                 goto fail;
2008         }
2009
2010         /* Write 1MB. */
2011         status = cli_writeall(cli,
2012                                 fnum,
2013                                 0,
2014                                 buf,
2015                                 0,
2016                                 buflen,
2017                                 NULL);
2018
2019         if (!NT_STATUS_IS_OK(status)) {
2020                 printf("write of %u to %s failed (%s)\n",
2021                         (unsigned int)buflen,
2022                         fname,
2023                         nt_errstr(status));
2024                 goto fail;
2025         }
2026
2027         status = check_size(cli, fnum, fname, buflen);
2028         if (!NT_STATUS_IS_OK(status)) {
2029                 goto fail;
2030         }
2031
2032         /* Now ftruncate. */
2033         for ( i = 0; i < 10; i++) {
2034                 status = cli_ftruncate(cli, fnum, i*1024);
2035                 if (!NT_STATUS_IS_OK(status)) {
2036                         printf("cli_ftruncate %u of %s failed (%s)\n",
2037                                 (unsigned int)i*1024,
2038                                 fname,
2039                                 nt_errstr(status));
2040                         goto fail;
2041                 }
2042                 status = check_size(cli, fnum, fname, i*1024);
2043                 if (!NT_STATUS_IS_OK(status)) {
2044                         goto fail;
2045                 }
2046         }
2047
2048         correct = true;
2049
2050   fail:
2051
2052         if (cli == NULL) {
2053                 return false;
2054         }
2055
2056         if (fnum != (uint16_t)-1) {
2057                 cli_close(cli, fnum);
2058         }
2059         cli_setatr(cli, fname, 0, 0);
2060         cli_unlink(cli, fname, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2061
2062         if (!torture_close_connection(cli)) {
2063                 correct = false;
2064         }
2065         return correct;
2066 }
2067
2068 /* Ensure SMB2 flush on directories behaves correctly. */
2069
2070 static bool test_dir_fsync(struct cli_state *cli, const char *path)
2071 {
2072         NTSTATUS status;
2073         uint64_t fid_persistent, fid_volatile;
2074         uint8_t *dir_data = NULL;
2075         uint32_t dir_data_length = 0;
2076
2077         /* Open directory - no write abilities. */
2078         status = smb2cli_create(cli->conn, cli->timeout, cli->smb2.session,
2079                         cli->smb2.tcon, path,
2080                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
2081                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
2082                         SEC_STD_SYNCHRONIZE|
2083                         SEC_DIR_LIST|
2084                         SEC_DIR_READ_ATTRIBUTE, /* desired_access, */
2085                         0, /* file_attributes, */
2086                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
2087                         FILE_OPEN, /* create_disposition, */
2088                         FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE, /* create_options, */
2089                         NULL, /* smb2_create_blobs *blobs */
2090                         &fid_persistent,
2091                         &fid_volatile,
2092                         NULL, NULL, NULL);
2093         if (!NT_STATUS_IS_OK(status)) {
2094                 printf("smb2cli_create '%s' (readonly) returned %s\n",
2095                         path,
2096                         nt_errstr(status));
2097                 return false;
2098         }
2099
2100         status = smb2cli_query_directory(
2101                 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
2102                 1, 0, 0, fid_persistent, fid_volatile, "*", 0xffff,
2103                 talloc_tos(), &dir_data, &dir_data_length);
2104
2105         if (!NT_STATUS_IS_OK(status)) {
2106                 printf("smb2cli_query_directory returned %s\n",
2107                         nt_errstr(status));
2108                 return false;
2109         }
2110
2111         /* Open directory no write access. Flush should fail. */
2112
2113         status = smb2cli_flush(cli->conn, cli->timeout, cli->smb2.session,
2114                                cli->smb2.tcon, fid_persistent, fid_volatile);
2115         if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
2116                 printf("smb2cli_flush on a read-only directory returned %s\n",
2117                         nt_errstr(status));
2118                 return false;
2119         }
2120
2121         status = smb2cli_close(cli->conn, cli->timeout, cli->smb2.session,
2122                                cli->smb2.tcon, 0, fid_persistent, fid_volatile);
2123         if (!NT_STATUS_IS_OK(status)) {
2124                 printf("smb2cli_close returned %s\n", nt_errstr(status));
2125                 return false;
2126         }
2127
2128         /* Open directory write-attributes only. Flush should still fail. */
2129
2130         status = smb2cli_create(cli->conn, cli->timeout, cli->smb2.session,
2131                         cli->smb2.tcon, path,
2132                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
2133                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
2134                         SEC_STD_SYNCHRONIZE|
2135                         SEC_DIR_LIST|
2136                         SEC_DIR_WRITE_ATTRIBUTE|
2137                         SEC_DIR_READ_ATTRIBUTE, /* desired_access, */
2138                         0, /* file_attributes, */
2139                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
2140                         FILE_OPEN, /* create_disposition, */
2141                         FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE, /* create_options, */
2142                         NULL, /* smb2_create_blobs *blobs */
2143                         &fid_persistent,
2144                         &fid_volatile,
2145                         NULL, NULL, NULL);
2146         if (!NT_STATUS_IS_OK(status)) {
2147                 printf("smb2cli_create '%s' (write attr) returned %s\n",
2148                         path,
2149                         nt_errstr(status));
2150                 return false;
2151         }
2152
2153         status = smb2cli_query_directory(
2154                 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
2155                 1, 0, 0, fid_persistent, fid_volatile, "*", 0xffff,
2156                 talloc_tos(), &dir_data, &dir_data_length);
2157
2158         if (!NT_STATUS_IS_OK(status)) {
2159                 printf("smb2cli_query_directory returned %s\n", nt_errstr(status));
2160                 return false;
2161         }
2162
2163         status = smb2cli_flush(cli->conn, cli->timeout, cli->smb2.session,
2164                                cli->smb2.tcon, fid_persistent, fid_volatile);
2165         if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
2166                 printf("smb2cli_flush on a write-attributes directory "
2167                         "returned %s\n",
2168                         nt_errstr(status));
2169                 return false;
2170         }
2171
2172         status = smb2cli_close(cli->conn, cli->timeout, cli->smb2.session,
2173                                cli->smb2.tcon, 0, fid_persistent, fid_volatile);
2174         if (!NT_STATUS_IS_OK(status)) {
2175                 printf("smb2cli_close returned %s\n", nt_errstr(status));
2176                 return false;
2177         }
2178
2179         /* Open directory with SEC_DIR_ADD_FILE access. Flush should now succeed. */
2180
2181         status = smb2cli_create(cli->conn, cli->timeout, cli->smb2.session,
2182                         cli->smb2.tcon, path,
2183                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
2184                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
2185                         SEC_STD_SYNCHRONIZE|
2186                         SEC_DIR_LIST|
2187                         SEC_DIR_ADD_FILE, /* desired_access, */
2188                         0, /* file_attributes, */
2189                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
2190                         FILE_OPEN, /* create_disposition, */
2191                         FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE, /* create_options, */
2192                         NULL, /* smb2_create_blobs *blobs */
2193                         &fid_persistent,
2194                         &fid_volatile,
2195                         NULL, NULL, NULL);
2196         if (!NT_STATUS_IS_OK(status)) {
2197                 printf("smb2cli_create '%s' (write FILE access) returned %s\n",
2198                         path,
2199                         nt_errstr(status));
2200                 return false;
2201         }
2202
2203         status = smb2cli_query_directory(
2204                 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
2205                 1, 0, 0, fid_persistent, fid_volatile, "*", 0xffff,
2206                 talloc_tos(), &dir_data, &dir_data_length);
2207
2208         if (!NT_STATUS_IS_OK(status)) {
2209                 printf("smb2cli_query_directory returned %s\n", nt_errstr(status));
2210                 return false;
2211         }
2212
2213         status = smb2cli_flush(cli->conn, cli->timeout, cli->smb2.session,
2214                                cli->smb2.tcon, fid_persistent, fid_volatile);
2215         if (!NT_STATUS_IS_OK(status)) {
2216                 printf("smb2cli_flush on a directory returned %s\n",
2217                         nt_errstr(status));
2218                 return false;
2219         }
2220
2221         status = smb2cli_close(cli->conn, cli->timeout, cli->smb2.session,
2222                                cli->smb2.tcon, 0, fid_persistent, fid_volatile);
2223         if (!NT_STATUS_IS_OK(status)) {
2224                 printf("smb2cli_close returned %s\n", nt_errstr(status));
2225                 return false;
2226         }
2227
2228         /* Open directory with SEC_DIR_ADD_FILE access. Flush should now succeed. */
2229
2230         status = smb2cli_create(cli->conn, cli->timeout, cli->smb2.session,
2231                         cli->smb2.tcon, path,
2232                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
2233                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
2234                         SEC_STD_SYNCHRONIZE|
2235                         SEC_DIR_LIST|
2236                         SEC_DIR_ADD_SUBDIR, /* desired_access, */
2237                         0, /* file_attributes, */
2238                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
2239                         FILE_OPEN, /* create_disposition, */
2240                         FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE, /* create_options, */
2241                         NULL, /* smb2_create_blobs *blobs */
2242                         &fid_persistent,
2243                         &fid_volatile,
2244                         NULL, NULL, NULL);
2245         if (!NT_STATUS_IS_OK(status)) {
2246                 printf("smb2cli_create '%s' (write DIR access) returned %s\n",
2247                         path,
2248                         nt_errstr(status));
2249                 return false;
2250         }
2251
2252         status = smb2cli_query_directory(
2253                 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
2254                 1, 0, 0, fid_persistent, fid_volatile, "*", 0xffff,
2255                 talloc_tos(), &dir_data, &dir_data_length);
2256
2257         if (!NT_STATUS_IS_OK(status)) {
2258                 printf("smb2cli_query_directory returned %s\n", nt_errstr(status));
2259                 return false;
2260         }
2261
2262         status = smb2cli_flush(cli->conn, cli->timeout, cli->smb2.session,
2263                                cli->smb2.tcon, fid_persistent, fid_volatile);
2264         if (!NT_STATUS_IS_OK(status)) {
2265                 printf("smb2cli_flush on a directory returned %s\n",
2266                         nt_errstr(status));
2267                 return false;
2268         }
2269
2270         status = smb2cli_close(cli->conn, cli->timeout, cli->smb2.session,
2271                                cli->smb2.tcon, 0, fid_persistent, fid_volatile);
2272         if (!NT_STATUS_IS_OK(status)) {
2273                 printf("smb2cli_close returned %s\n", nt_errstr(status));
2274                 return false;
2275         }
2276
2277
2278         return true;
2279 }
2280
2281 bool run_smb2_dir_fsync(int dummy)
2282 {
2283         struct cli_state *cli = NULL;
2284         NTSTATUS status;
2285         bool bret = false;
2286         const char *dname = "fsync_test_dir";
2287
2288         printf("Starting SMB2-DIR-FSYNC\n");
2289
2290         if (!torture_init_connection(&cli)) {
2291                 return false;
2292         }
2293
2294         status = smbXcli_negprot(cli->conn, cli->timeout,
2295                                  PROTOCOL_SMB2_02, PROTOCOL_SMB2_02);
2296         if (!NT_STATUS_IS_OK(status)) {
2297                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
2298                 return false;
2299         }
2300
2301         status = cli_session_setup_creds(cli, torture_creds);
2302         if (!NT_STATUS_IS_OK(status)) {
2303                 printf("cli_session_setup returned %s\n", nt_errstr(status));
2304                 return false;
2305         }
2306
2307         status = cli_tree_connect(cli, share, "?????", NULL);
2308         if (!NT_STATUS_IS_OK(status)) {
2309                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
2310                 return false;
2311         }
2312
2313         (void)cli_rmdir(cli, dname);
2314         status = cli_mkdir(cli, dname);
2315         if (!NT_STATUS_IS_OK(status)) {
2316                 printf("cli_mkdir(%s) returned %s\n",
2317                         dname,
2318                         nt_errstr(status));
2319                 return false;
2320         }
2321
2322         /* Test on a subdirectory. */
2323         bret = test_dir_fsync(cli, dname);
2324         if (bret == false) {
2325                 (void)cli_rmdir(cli, dname);
2326                 return false;
2327         }
2328         (void)cli_rmdir(cli, dname);
2329
2330         /* Test on the root handle of a share. */
2331         bret = test_dir_fsync(cli, "");
2332         if (bret == false) {
2333                 return false;
2334         }
2335         return true;
2336 }
2337
2338 bool run_smb2_path_slash(int dummy)
2339 {
2340         struct cli_state *cli = NULL;
2341         NTSTATUS status;
2342         uint64_t fid_persistent;
2343         uint64_t fid_volatile;
2344         const char *dname_noslash = "smb2_dir_slash";
2345         const char *dname_backslash = "smb2_dir_slash\\";
2346         const char *dname_slash = "smb2_dir_slash/";
2347         const char *fname_noslash = "smb2_file_slash";
2348         const char *fname_backslash = "smb2_file_slash\\";
2349         const char *fname_slash = "smb2_file_slash/";
2350
2351         printf("Starting SMB2-PATH-SLASH\n");
2352
2353         if (!torture_init_connection(&cli)) {
2354                 return false;
2355         }
2356
2357         status = smbXcli_negprot(cli->conn, cli->timeout,
2358                                  PROTOCOL_SMB2_02, PROTOCOL_SMB2_02);
2359         if (!NT_STATUS_IS_OK(status)) {
2360                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
2361                 return false;
2362         }
2363
2364         status = cli_session_setup_creds(cli, torture_creds);
2365         if (!NT_STATUS_IS_OK(status)) {
2366                 printf("cli_session_setup returned %s\n", nt_errstr(status));
2367                 return false;
2368         }
2369
2370         status = cli_tree_connect(cli, share, "?????", NULL);
2371         if (!NT_STATUS_IS_OK(status)) {
2372                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
2373                 return false;
2374         }
2375
2376         (void)cli_unlink(cli, dname_noslash, 0);
2377         (void)cli_rmdir(cli, dname_noslash);
2378         (void)cli_unlink(cli, fname_noslash, 0);
2379         (void)cli_rmdir(cli, fname_noslash);
2380
2381         /* Try to create a directory with the backslash name. */
2382         status = smb2cli_create(cli->conn,
2383                         cli->timeout,
2384                         cli->smb2.session,
2385                         cli->smb2.tcon,
2386                         dname_backslash,
2387                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
2388                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
2389                         FILE_READ_DATA|FILE_READ_ATTRIBUTES, /* desired_access, */
2390                         0, /* file_attributes, */
2391                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
2392                         FILE_CREATE, /* create_disposition, */
2393                         FILE_DIRECTORY_FILE, /* create_options, */
2394                         NULL, /* smb2_create_blobs *blobs */
2395                         &fid_persistent,
2396                         &fid_volatile,
2397                         NULL, NULL, NULL);
2398
2399         /* directory ending in '\\' should be success. */
2400
2401         if (!NT_STATUS_IS_OK(status)) {
2402                 printf("smb2cli_create '%s' returned %s - "
2403                         "should be NT_STATUS_OK\n",
2404                         dname_backslash,
2405                         nt_errstr(status));
2406                 return false;
2407         }
2408         status = smb2cli_close(cli->conn,
2409                                 cli->timeout,
2410                                 cli->smb2.session,
2411                                 cli->smb2.tcon,
2412                                 0,
2413                                 fid_persistent,
2414                                 fid_volatile);
2415         if (!NT_STATUS_IS_OK(status)) {
2416                 printf("smb2cli_close returned %s\n", nt_errstr(status));
2417                 return false;
2418         }
2419
2420         (void)cli_rmdir(cli, dname_noslash);
2421
2422         /* Try to create a directory with the slash name. */
2423         status = smb2cli_create(cli->conn,
2424                         cli->timeout,
2425                         cli->smb2.session,
2426                         cli->smb2.tcon,
2427                         dname_slash,
2428                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
2429                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
2430                         FILE_READ_DATA|FILE_READ_ATTRIBUTES, /* desired_access, */
2431                         0, /* file_attributes, */
2432                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
2433                         FILE_CREATE, /* create_disposition, */
2434                         FILE_DIRECTORY_FILE, /* create_options, */
2435                         NULL, /* smb2_create_blobs *blobs */
2436                         &fid_persistent,
2437                         &fid_volatile,
2438                         NULL, NULL, NULL);
2439
2440         /* directory ending in '/' is an error. */
2441         if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_INVALID)) {
2442                 printf("smb2cli_create '%s' returned %s - "
2443                         "should be NT_STATUS_OBJECT_NAME_INVALID\n",
2444                         dname_slash,
2445                         nt_errstr(status));
2446                 if (NT_STATUS_IS_OK(status)) {
2447                         (void)smb2cli_close(cli->conn,
2448                                         cli->timeout,
2449                                         cli->smb2.session,
2450                                         cli->smb2.tcon,
2451                                         0,
2452                                         fid_persistent,
2453                                         fid_volatile);
2454                 }
2455                 (void)cli_rmdir(cli, dname_noslash);
2456                 return false;
2457         }
2458
2459         (void)cli_rmdir(cli, dname_noslash);
2460
2461         /* Try to create a file with the backslash name. */
2462         status = smb2cli_create(cli->conn,
2463                         cli->timeout,
2464                         cli->smb2.session,
2465                         cli->smb2.tcon,
2466                         fname_backslash,
2467                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
2468                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
2469                         FILE_READ_DATA|FILE_READ_ATTRIBUTES, /* desired_access, */
2470                         0, /* file_attributes, */
2471                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
2472                         FILE_CREATE, /* create_disposition, */
2473                         FILE_NON_DIRECTORY_FILE, /* create_options, */
2474                         NULL, /* smb2_create_blobs *blobs */
2475                         &fid_persistent,
2476                         &fid_volatile,
2477                         NULL, NULL, NULL);
2478
2479         /* file ending in '\\' should be error. */
2480
2481         if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_INVALID)) {
2482                 printf("smb2cli_create '%s' returned %s - "
2483                         "should be NT_STATUS_OBJECT_NAME_INVALID\n",
2484                         fname_backslash,
2485                         nt_errstr(status));
2486                 if (NT_STATUS_IS_OK(status)) {
2487                         (void)smb2cli_close(cli->conn,
2488                                         cli->timeout,
2489                                         cli->smb2.session,
2490                                         cli->smb2.tcon,
2491                                         0,
2492                                         fid_persistent,
2493                                         fid_volatile);
2494                 }
2495                 (void)cli_unlink(cli, fname_noslash, 0);
2496                 return false;
2497         }
2498
2499         (void)cli_unlink(cli, fname_noslash, 0);
2500
2501         /* Try to create a file with the slash name. */
2502         status = smb2cli_create(cli->conn,
2503                         cli->timeout,
2504                         cli->smb2.session,
2505                         cli->smb2.tcon,
2506                         fname_slash,
2507                         SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
2508                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
2509                         FILE_READ_DATA|FILE_READ_ATTRIBUTES, /* desired_access, */
2510                         0, /* file_attributes, */
2511                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
2512                         FILE_CREATE, /* create_disposition, */
2513                         FILE_NON_DIRECTORY_FILE, /* create_options, */
2514                         NULL, /* smb2_create_blobs *blobs */
2515                         &fid_persistent,
2516                         &fid_volatile,
2517                         NULL, NULL, NULL);
2518
2519         /* file ending in '/' should be error. */
2520
2521         if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_INVALID)) {
2522                 printf("smb2cli_create '%s' returned %s - "
2523                         "should be NT_STATUS_OBJECT_NAME_INVALID\n",
2524                         fname_slash,
2525                         nt_errstr(status));
2526                 if (NT_STATUS_IS_OK(status)) {
2527                         (void)smb2cli_close(cli->conn,
2528                                         cli->timeout,
2529                                         cli->smb2.session,
2530                                         cli->smb2.tcon,
2531                                         0,
2532                                         fid_persistent,
2533                                         fid_volatile);
2534                 }
2535                 (void)cli_unlink(cli, fname_noslash, 0);
2536                 return false;
2537         }
2538
2539         (void)cli_unlink(cli, fname_noslash, 0);
2540         return true;
2541 }
2542
2543 /*
2544  * NB. This can only work against a server where
2545  * the connecting user has been granted SeSecurityPrivilege.
2546  *
2547  *  1). Create a test file.
2548  *  2). Open with SEC_FLAG_SYSTEM_SECURITY *only*. ACCESS_DENIED -
2549  *             NB. SMB2-only behavior.
2550  *  3). Open with SEC_FLAG_SYSTEM_SECURITY|FILE_WRITE_ATTRIBUTES.
2551  *  4). Write SACL. Should fail with ACCESS_DENIED (seems to need WRITE_DAC).
2552  *  5). Close (3).
2553  *  6). Open with SEC_FLAG_SYSTEM_SECURITY|SEC_STD_WRITE_DAC.
2554  *  7). Write SACL. Success.
2555  *  8). Close (4).
2556  *  9). Open with SEC_FLAG_SYSTEM_SECURITY|READ_ATTRIBUTES.
2557  *  10). Read SACL. Success.
2558  *  11). Read DACL. Should fail with ACCESS_DENIED (no READ_CONTROL).
2559  *  12). Close (9).
2560  */
2561
2562 bool run_smb2_sacl(int dummy)
2563 {
2564         struct cli_state *cli = NULL;
2565         NTSTATUS status;
2566         struct security_descriptor *sd_dacl = NULL;
2567         struct security_descriptor *sd_sacl = NULL;
2568         const char *fname = "sacl_test_file";
2569         uint16_t fnum = (uint16_t)-1;
2570
2571         printf("Starting SMB2-SACL\n");
2572
2573         if (!torture_init_connection(&cli)) {
2574                 return false;
2575         }
2576
2577         status = smbXcli_negprot(cli->conn,
2578                                 cli->timeout,
2579                                 PROTOCOL_SMB2_02,
2580                                 PROTOCOL_SMB3_11);
2581         if (!NT_STATUS_IS_OK(status)) {
2582                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
2583                 return false;
2584         }
2585
2586         status = cli_session_setup_creds(cli, torture_creds);
2587         if (!NT_STATUS_IS_OK(status)) {
2588                 printf("cli_session_setup returned %s\n", nt_errstr(status));
2589                 return false;
2590         }
2591
2592         status = cli_tree_connect(cli, share, "?????", NULL);
2593         if (!NT_STATUS_IS_OK(status)) {
2594                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
2595                 return false;
2596         }
2597
2598         (void)cli_unlink(cli, fname, 0);
2599
2600         /* First create a file. */
2601         status = cli_ntcreate(cli,
2602                                 fname,
2603                                 0,
2604                                 GENERIC_ALL_ACCESS,
2605                                 FILE_ATTRIBUTE_NORMAL,
2606                                 FILE_SHARE_NONE,
2607                                 FILE_CREATE,
2608                                 0,
2609                                 0,
2610                                 &fnum,
2611                                 NULL);
2612
2613         if (!NT_STATUS_IS_OK(status)) {
2614                 printf("Create of %s failed (%s)\n",
2615                         fname,
2616                         nt_errstr(status));
2617                 goto fail;
2618         }
2619
2620         cli_close(cli, fnum);
2621         fnum = (uint16_t)-1;
2622
2623         /*
2624          * Now try to open with *only* SEC_FLAG_SYSTEM_SECURITY.
2625          * This should fail with NT_STATUS_ACCESS_DENIED - but
2626          * only against an SMB2 server. SMB1 allows this as tested
2627          * in SMB1-SYSTEM-SECURITY.
2628          */
2629
2630         status = cli_smb2_create_fnum(cli,
2631                         fname,
2632                         SMB2_OPLOCK_LEVEL_NONE,
2633                         SMB2_IMPERSONATION_IMPERSONATION,
2634                         SEC_FLAG_SYSTEM_SECURITY, /* desired access */
2635                         0, /* file_attributes, */
2636                         FILE_SHARE_READ|
2637                                 FILE_SHARE_WRITE|
2638                                 FILE_SHARE_DELETE, /* share_access, */
2639                         FILE_OPEN, /* create_disposition, */
2640                         FILE_NON_DIRECTORY_FILE, /* create_options, */
2641                         NULL, /* in_cblobs. */
2642                         &fnum, /* fnum */
2643                         NULL, /* smb_create_returns  */
2644                         talloc_tos(), /* mem_ctx */
2645                         NULL); /* out_cblobs */
2646
2647         if (NT_STATUS_EQUAL(status, NT_STATUS_PRIVILEGE_NOT_HELD)) {
2648                 printf("SMB2-SACL-TEST can only work with a user "
2649                         "who has been granted SeSecurityPrivilege.\n"
2650                         "This is the "
2651                         "\"Manage auditing and security log\""
2652                         "privilege setting on Windows\n");
2653                 goto fail;
2654         }
2655
2656         if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
2657                 printf("open file %s with SEC_FLAG_SYSTEM_SECURITY only: "
2658                         "got %s - should fail with ACCESS_DENIED\n",
2659                         fname,
2660                         nt_errstr(status));
2661                 goto fail;
2662         }
2663
2664         /*
2665          * Open with SEC_FLAG_SYSTEM_SECURITY|FILE_WRITE_ATTRIBUTES.
2666          */
2667
2668         status = cli_smb2_create_fnum(cli,
2669                         fname,
2670                         SMB2_OPLOCK_LEVEL_NONE,
2671                         SMB2_IMPERSONATION_IMPERSONATION,
2672                         SEC_FLAG_SYSTEM_SECURITY|
2673                                 FILE_WRITE_ATTRIBUTES, /* desired access */
2674                         0, /* file_attributes, */
2675                         FILE_SHARE_READ|
2676                                 FILE_SHARE_WRITE|
2677                                 FILE_SHARE_DELETE, /* share_access, */
2678                         FILE_OPEN, /* create_disposition, */
2679                         FILE_NON_DIRECTORY_FILE, /* create_options, */
2680                         NULL, /* in_cblobs. */
2681                         &fnum, /* fnum */
2682                         NULL, /* smb_create_returns  */
2683                         talloc_tos(), /* mem_ctx */
2684                         NULL); /* out_cblobs */
2685
2686         if (!NT_STATUS_IS_OK(status)) {
2687                 printf("Open of %s with (SEC_FLAG_SYSTEM_SECURITY|"
2688                         "FILE_WRITE_ATTRIBUTES) failed (%s)\n",
2689                         fname,
2690                         nt_errstr(status));
2691                 goto fail;
2692         }
2693
2694         /* Create an SD with a SACL. */
2695         sd_sacl = security_descriptor_sacl_create(talloc_tos(),
2696                                 0,
2697                                 NULL, /* owner. */
2698                                 NULL, /* group. */
2699                                 /* first ACE. */
2700                                 SID_WORLD,
2701                                 SEC_ACE_TYPE_SYSTEM_AUDIT,
2702                                 SEC_GENERIC_ALL,
2703                                 SEC_ACE_FLAG_FAILED_ACCESS,
2704                                 NULL);
2705
2706         if (sd_sacl == NULL) {
2707                 printf("Out of memory creating SACL\n");
2708                 goto fail;
2709         }
2710
2711         /*
2712          * Write the SACL SD. This should fail
2713          * even though we have SEC_FLAG_SYSTEM_SECURITY,
2714          * as it seems to also need WRITE_DAC access.
2715          */
2716         status = cli_set_security_descriptor(cli,
2717                                 fnum,
2718                                 SECINFO_DACL|SECINFO_SACL,
2719                                 sd_sacl);
2720
2721         if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
2722                 printf("Writing SACL on file %s got (%s) "
2723                         "should have failed with ACCESS_DENIED.\n",
2724                         fname,
2725                         nt_errstr(status));
2726                 goto fail;
2727         }
2728
2729         /* And close. */
2730         cli_smb2_close_fnum(cli, fnum);
2731         fnum = (uint16_t)-1;
2732
2733         /*
2734          * Open with SEC_FLAG_SYSTEM_SECURITY|SEC_STD_WRITE_DAC.
2735          */
2736
2737         status = cli_smb2_create_fnum(cli,
2738                         fname,
2739                         SMB2_OPLOCK_LEVEL_NONE,
2740                         SMB2_IMPERSONATION_IMPERSONATION,
2741                         SEC_FLAG_SYSTEM_SECURITY|
2742                                 SEC_STD_WRITE_DAC, /* desired access */
2743                         0, /* file_attributes, */
2744                         FILE_SHARE_READ|
2745                                 FILE_SHARE_WRITE|
2746                                 FILE_SHARE_DELETE, /* share_access, */
2747                         FILE_OPEN, /* create_disposition, */
2748                         FILE_NON_DIRECTORY_FILE, /* create_options, */
2749                         NULL, /* in_cblobs. */
2750                         &fnum, /* fnum */
2751                         NULL, /* smb_create_returns  */
2752                         talloc_tos(), /* mem_ctx */
2753                         NULL); /* out_cblobs */
2754
2755         if (!NT_STATUS_IS_OK(status)) {
2756                 printf("Open of %s with (SEC_FLAG_SYSTEM_SECURITY|"
2757                         "FILE_WRITE_ATTRIBUTES) failed (%s)\n",
2758                         fname,
2759                         nt_errstr(status));
2760                 goto fail;
2761         }
2762
2763         /*
2764          * Write the SACL SD. This should now succeed
2765          * as we have both SEC_FLAG_SYSTEM_SECURITY
2766          * and WRITE_DAC access.
2767          */
2768         status = cli_set_security_descriptor(cli,
2769                                 fnum,
2770                                 SECINFO_DACL|SECINFO_SACL,
2771                                 sd_sacl);
2772
2773         if (!NT_STATUS_IS_OK(status)) {
2774                 printf("cli_set_security_descriptor SACL "
2775                         "on file %s failed (%s)\n",
2776                         fname,
2777                         nt_errstr(status));
2778                 goto fail;
2779         }
2780
2781         /* And close. */
2782         cli_smb2_close_fnum(cli, fnum);
2783         fnum = (uint16_t)-1;
2784
2785         /* We're done with the sacl we made. */
2786         TALLOC_FREE(sd_sacl);
2787
2788         /*
2789          * Now try to open with SEC_FLAG_SYSTEM_SECURITY|READ_ATTRIBUTES.
2790          * This gives us access to the SACL.
2791          */
2792
2793         status = cli_smb2_create_fnum(cli,
2794                         fname,
2795                         SMB2_OPLOCK_LEVEL_NONE,
2796                         SMB2_IMPERSONATION_IMPERSONATION,
2797                         SEC_FLAG_SYSTEM_SECURITY|
2798                                 FILE_READ_ATTRIBUTES, /* desired access */
2799                         0, /* file_attributes, */
2800                         FILE_SHARE_READ|
2801                                 FILE_SHARE_WRITE|
2802                                 FILE_SHARE_DELETE, /* share_access, */
2803                         FILE_OPEN, /* create_disposition, */
2804                         FILE_NON_DIRECTORY_FILE, /* create_options, */
2805                         NULL, /* in_cblobs. */
2806                         &fnum, /* fnum */
2807                         NULL, /* smb_create_returns  */
2808                         talloc_tos(), /* mem_ctx */
2809                         NULL); /* out_cblobs */
2810
2811         if (!NT_STATUS_IS_OK(status)) {
2812                 printf("Open of %s with (SEC_FLAG_SYSTEM_SECURITY|"
2813                         "FILE_READ_ATTRIBUTES) failed (%s)\n",
2814                         fname,
2815                         nt_errstr(status));
2816                 goto fail;
2817         }
2818
2819         /* Try and read the SACL - should succeed. */
2820         status = cli_query_security_descriptor(
2821                 cli, fnum, SECINFO_SACL, talloc_tos(), &sd_sacl);
2822
2823         if (!NT_STATUS_IS_OK(status)) {
2824                 printf("Read SACL from file %s failed (%s)\n",
2825                         fname,
2826                         nt_errstr(status));
2827                 goto fail;
2828         }
2829
2830         TALLOC_FREE(sd_sacl);
2831
2832         /*
2833          * Try and read the DACL - should fail as we have
2834          * no READ_DAC access.
2835          */
2836         status = cli_query_security_descriptor(
2837                 cli, fnum, SECINFO_DACL, talloc_tos(), &sd_sacl);
2838
2839         if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
2840                 printf("Reading DACL on file %s got (%s) "
2841                         "should have failed with ACCESS_DENIED.\n",
2842                         fname,
2843                         nt_errstr(status));
2844                 goto fail;
2845         }
2846
2847         if (fnum != (uint16_t)-1) {
2848                 cli_smb2_close_fnum(cli, fnum);
2849                 fnum = (uint16_t)-1;
2850         }
2851
2852         TALLOC_FREE(sd_dacl);
2853         TALLOC_FREE(sd_sacl);
2854
2855         (void)cli_unlink(cli, fname, 0);
2856         return true;
2857
2858   fail:
2859
2860         TALLOC_FREE(sd_dacl);
2861         TALLOC_FREE(sd_sacl);
2862
2863         if (fnum != (uint16_t)-1) {
2864                 cli_smb2_close_fnum(cli, fnum);
2865                 fnum = (uint16_t)-1;
2866         }
2867
2868         (void)cli_unlink(cli, fname, 0);
2869         return false;
2870 }
2871
2872 bool run_smb2_quota1(int dummy)
2873 {
2874         struct cli_state *cli = NULL;
2875         NTSTATUS status;
2876         uint16_t fnum = (uint16_t)-1;
2877         SMB_NTQUOTA_STRUCT qt = {0};
2878
2879         printf("Starting SMB2-QUOTA1\n");
2880
2881         if (!torture_init_connection(&cli)) {
2882                 return false;
2883         }
2884
2885         status = smbXcli_negprot(cli->conn,
2886                                 cli->timeout,
2887                                 PROTOCOL_SMB2_02,
2888                                 PROTOCOL_SMB3_11);
2889         if (!NT_STATUS_IS_OK(status)) {
2890                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
2891                 return false;
2892         }
2893
2894         status = cli_session_setup_creds(cli, torture_creds);
2895         if (!NT_STATUS_IS_OK(status)) {
2896                 printf("cli_session_setup returned %s\n", nt_errstr(status));
2897                 return false;
2898         }
2899
2900         status = cli_tree_connect(cli, share, "?????", NULL);
2901         if (!NT_STATUS_IS_OK(status)) {
2902                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
2903                 return false;
2904         }
2905
2906         status = cli_smb2_create_fnum(
2907                 cli,
2908                 "\\",
2909                 SMB2_OPLOCK_LEVEL_NONE,
2910                 SMB2_IMPERSONATION_IMPERSONATION,
2911                 SEC_GENERIC_READ, /* desired access */
2912                 0, /* file_attributes, */
2913                 FILE_SHARE_READ|
2914                 FILE_SHARE_WRITE|
2915                 FILE_SHARE_DELETE, /* share_access, */
2916                 FILE_OPEN, /* create_disposition, */
2917                 FILE_DIRECTORY_FILE, /* create_options, */
2918                 NULL, /* in_cblobs. */
2919                 &fnum, /* fnum */
2920                 NULL, /* smb_create_returns  */
2921                 NULL, /* mem_ctx */
2922                 NULL); /* out_cblobs */
2923         if (!NT_STATUS_IS_OK(status)) {
2924                 printf("cli_smb2_create_fnum failed: %s\n", nt_errstr(status));
2925                 return false;
2926         }
2927
2928         status = cli_smb2_get_user_quota(cli, fnum, &qt);
2929         if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
2930                 printf("cli_smb2_get_user_quota returned %s, expected "
2931                        "NT_STATUS_INVALID_HANDLE\n",
2932                        nt_errstr(status));
2933                 return false;
2934         }
2935
2936         return true;
2937 }
2938
2939 bool run_smb2_stream_acl(int dummy)
2940 {
2941         struct cli_state *cli = NULL;
2942         NTSTATUS status;
2943         uint16_t fnum = (uint16_t)-1;
2944         const char *fname = "stream_acl_test_file";
2945         const char *sname = "stream_acl_test_file:streamname";
2946         struct security_descriptor *sd_dacl = NULL;
2947         bool ret = false;
2948
2949         printf("SMB2 stream acl\n");
2950
2951         if (!torture_init_connection(&cli)) {
2952                 return false;
2953         }
2954
2955         status = smbXcli_negprot(cli->conn,
2956                                 cli->timeout,
2957                                 PROTOCOL_SMB2_02,
2958                                 PROTOCOL_SMB3_11);
2959         if (!NT_STATUS_IS_OK(status)) {
2960                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
2961                 return false;
2962         }
2963
2964         status = cli_session_setup_creds(cli, torture_creds);
2965         if (!NT_STATUS_IS_OK(status)) {
2966                 printf("cli_session_setup returned %s\n", nt_errstr(status));
2967                 return false;
2968         }
2969
2970         status = cli_tree_connect(cli, share, "?????", NULL);
2971         if (!NT_STATUS_IS_OK(status)) {
2972                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
2973                 return false;
2974         }
2975
2976         /* Ensure file doesn't exist. */
2977         (void)cli_unlink(cli, fname, 0);
2978
2979         /* Create the file. */
2980         status = cli_ntcreate(cli,
2981                                 fname,
2982                                 0,
2983                                 GENERIC_ALL_ACCESS,
2984                                 FILE_ATTRIBUTE_NORMAL,
2985                                 FILE_SHARE_NONE,
2986                                 FILE_CREATE,
2987                                 0,
2988                                 0,
2989                                 &fnum,
2990                                 NULL);
2991
2992         if (!NT_STATUS_IS_OK(status)) {
2993                 printf("Create of %s failed (%s)\n",
2994                         fname,
2995                         nt_errstr(status));
2996                 goto fail;
2997         }
2998
2999         /* Close the handle. */
3000         cli_smb2_close_fnum(cli, fnum);
3001         fnum = (uint16_t)-1;
3002
3003         /* Create the stream. */
3004         status = cli_ntcreate(cli,
3005                                 sname,
3006                                 0,
3007                                 FILE_READ_DATA|
3008                                         SEC_STD_READ_CONTROL|
3009                                         SEC_STD_WRITE_DAC,
3010                                 FILE_ATTRIBUTE_NORMAL,
3011                                 FILE_SHARE_NONE,
3012                                 FILE_CREATE,
3013                                 0,
3014                                 0,
3015                                 &fnum,
3016                                 NULL);
3017
3018         if (!NT_STATUS_IS_OK(status)) {
3019                 printf("Create of %s failed (%s)\n",
3020                         sname,
3021                         nt_errstr(status));
3022                 goto fail;
3023         }
3024
3025         /* Close the handle. */
3026         cli_smb2_close_fnum(cli, fnum);
3027         fnum = (uint16_t)-1;
3028
3029         /*
3030          * Open the stream - for Samba this ensures
3031          * we prove we have a pathref fsp.
3032          */
3033         status = cli_ntcreate(cli,
3034                                 sname,
3035                                 0,
3036                                 FILE_READ_DATA|
3037                                         SEC_STD_READ_CONTROL|
3038                                         SEC_STD_WRITE_DAC,
3039                                 FILE_ATTRIBUTE_NORMAL,
3040                                 FILE_SHARE_NONE,
3041                                 FILE_OPEN,
3042                                 0,
3043                                 0,
3044                                 &fnum,
3045                                 NULL);
3046
3047         if (!NT_STATUS_IS_OK(status)) {
3048                 printf("Open of %s failed (%s)\n",
3049                         sname,
3050                         nt_errstr(status));
3051                 goto fail;
3052         }
3053
3054         /* Read the security descriptor off the stream handle. */
3055         status = cli_query_security_descriptor(cli,
3056                                 fnum,
3057                                 SECINFO_DACL,
3058                                 talloc_tos(),
3059                                 &sd_dacl);
3060
3061         if (!NT_STATUS_IS_OK(status)) {
3062                 printf("Reading DACL on stream %s got (%s)\n",
3063                         sname,
3064                         nt_errstr(status));
3065                 goto fail;
3066         }
3067
3068         if (sd_dacl == NULL || sd_dacl->dacl == NULL ||
3069                         sd_dacl->dacl->num_aces < 1) {
3070                 printf("Invalid DACL returned on stream %s "
3071                         "(this should not happen)\n",
3072                         sname);
3073                 goto fail;
3074         }
3075
3076         /*
3077          * Ensure it allows FILE_READ_DATA in the first ace.
3078          * It always should.
3079          */
3080         if ((sd_dacl->dacl->aces[0].access_mask & FILE_READ_DATA) == 0) {
3081                 printf("DACL->ace[0] returned on stream %s "
3082                         "doesn't have read access (should not happen)\n",
3083                         sname);
3084                 goto fail;
3085         }
3086
3087         /* Remove FILE_READ_DATA from the first ace and set. */
3088         sd_dacl->dacl->aces[0].access_mask &= ~FILE_READ_DATA;
3089
3090         status = cli_set_security_descriptor(cli,
3091                                 fnum,
3092                                 SECINFO_DACL,
3093                                 sd_dacl);
3094
3095         if (!NT_STATUS_IS_OK(status)) {
3096                 printf("Setting DACL on stream %s got (%s)\n",
3097                         sname,
3098                         nt_errstr(status));
3099                 goto fail;
3100         }
3101
3102         TALLOC_FREE(sd_dacl);
3103
3104         /* Read again and check it changed. */
3105         status = cli_query_security_descriptor(cli,
3106                                 fnum,
3107                                 SECINFO_DACL,
3108                                 talloc_tos(),
3109                                 &sd_dacl);
3110
3111         if (!NT_STATUS_IS_OK(status)) {
3112                 printf("Reading DACL on stream %s got (%s)\n",
3113                         sname,
3114                         nt_errstr(status));
3115                 goto fail;
3116         }
3117
3118         if (sd_dacl == NULL || sd_dacl->dacl == NULL ||
3119                         sd_dacl->dacl->num_aces < 1) {
3120                 printf("Invalid DACL (1) returned on stream %s "
3121                         "(this should not happen)\n",
3122                         sname);
3123                 goto fail;
3124         }
3125
3126         /* FILE_READ_DATA should be gone from the first ace. */
3127         if ((sd_dacl->dacl->aces[0].access_mask & FILE_READ_DATA) != 0) {
3128                 printf("DACL on stream %s did not change\n",
3129                         sname);
3130                 goto fail;
3131         }
3132
3133         ret = true;
3134
3135   fail:
3136
3137         if (fnum != (uint16_t)-1) {
3138                 cli_smb2_close_fnum(cli, fnum);
3139                 fnum = (uint16_t)-1;
3140         }
3141
3142         (void)cli_unlink(cli, fname, 0);
3143         return ret;
3144 }
3145
3146 static NTSTATUS list_fn(struct file_info *finfo,
3147                         const char *name,
3148                         void *state)
3149 {
3150         bool *matched = (bool *)state;
3151         if (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) {
3152                 *matched = true;
3153         }
3154         return NT_STATUS_OK;
3155 }
3156
3157 /*
3158  * Must be run against a share with "smbd async dosmode = yes".
3159  * Checks we can return DOS attriutes other than "N".
3160  * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14758
3161  */
3162
3163 bool run_list_dir_async_test(int dummy)
3164 {
3165         struct cli_state *cli = NULL;
3166         NTSTATUS status;
3167         const char *dname = "ASYNC_DIR";
3168         bool ret = false;
3169         bool matched = false;
3170
3171         printf("SMB2 list dir async\n");
3172
3173         if (!torture_init_connection(&cli)) {
3174                 return false;
3175         }
3176
3177         status = smbXcli_negprot(cli->conn,
3178                                 cli->timeout,
3179                                 PROTOCOL_SMB2_02,
3180                                 PROTOCOL_SMB3_11);
3181         if (!NT_STATUS_IS_OK(status)) {
3182                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
3183                 return false;
3184         }
3185
3186         status = cli_session_setup_creds(cli, torture_creds);
3187         if (!NT_STATUS_IS_OK(status)) {
3188                 printf("cli_session_setup returned %s\n", nt_errstr(status));
3189                 return false;
3190         }
3191
3192         status = cli_tree_connect(cli, share, "?????", NULL);
3193         if (!NT_STATUS_IS_OK(status)) {
3194                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
3195                 return false;
3196         }
3197
3198         /* Ensure directory doesn't exist. */
3199         (void)cli_rmdir(cli, dname);
3200
3201         status = cli_mkdir(cli, dname);
3202         if (!NT_STATUS_IS_OK(status)) {
3203                 printf("cli_mkdir %s returned %s\n", dname, nt_errstr(status));
3204                 return false;
3205         }
3206
3207         status = cli_list(cli,
3208                           dname,
3209                           FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_DIRECTORY,
3210                           list_fn,
3211                           &matched);
3212         if (!NT_STATUS_IS_OK(status)) {
3213                 printf("cli_list %s returned %s\n", dname, nt_errstr(status));
3214                 goto fail;
3215         }
3216
3217         if (!matched) {
3218                 printf("Failed to find %s\n", dname);
3219                 goto fail;
3220         }
3221
3222         ret = true;
3223
3224   fail:
3225
3226         (void)cli_rmdir(cli, dname);
3227         return ret;
3228 }
3229
3230 /*
3231  * Test delete a directory fails if a file is created
3232  * in a directory after the delete on close is set.
3233  * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14892
3234  */
3235
3236 bool run_delete_on_close_non_empty(int dummy)
3237 {
3238         struct cli_state *cli = NULL;
3239         NTSTATUS status;
3240         const char *dname = "DEL_ON_CLOSE_DIR";
3241         const char *fname = "DEL_ON_CLOSE_DIR\\testfile";
3242         uint16_t fnum = (uint16_t)-1;
3243         uint16_t fnum1 = (uint16_t)-1;
3244         bool ret = false;
3245
3246         printf("SMB2 delete on close nonempty\n");
3247
3248         if (!torture_init_connection(&cli)) {
3249                 return false;
3250         }
3251
3252         status = smbXcli_negprot(cli->conn,
3253                                 cli->timeout,
3254                                 PROTOCOL_SMB2_02,
3255                                 PROTOCOL_SMB3_11);
3256         if (!NT_STATUS_IS_OK(status)) {
3257                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
3258                 return false;
3259         }
3260
3261         status = cli_session_setup_creds(cli, torture_creds);
3262         if (!NT_STATUS_IS_OK(status)) {
3263                 printf("cli_session_setup returned %s\n", nt_errstr(status));
3264                 return false;
3265         }
3266
3267         status = cli_tree_connect(cli, share, "?????", NULL);
3268         if (!NT_STATUS_IS_OK(status)) {
3269                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
3270                 return false;
3271         }
3272
3273         /* Ensure directory doesn't exist. */
3274         (void)cli_unlink(cli,
3275                          fname,
3276                          FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
3277         (void)cli_rmdir(cli, dname);
3278
3279         /* Create target directory. */
3280         status = cli_ntcreate(cli,
3281                                 dname,
3282                                 0,
3283                                 DELETE_ACCESS|FILE_READ_DATA,
3284                                 FILE_ATTRIBUTE_DIRECTORY,
3285                                 FILE_SHARE_READ|
3286                                         FILE_SHARE_WRITE|
3287                                         FILE_SHARE_DELETE,
3288                                 FILE_CREATE,
3289                                 FILE_DIRECTORY_FILE,
3290                                 0,
3291                                 &fnum,
3292                                 NULL);
3293         if (!NT_STATUS_IS_OK(status)) {
3294                 printf("cli_ntcreate for directory %s returned %s\n",
3295                                 dname,
3296                                 nt_errstr(status));
3297                 goto out;
3298         }
3299
3300         /* Now set the delete on close bit. */
3301         status = cli_nt_delete_on_close(cli, fnum, 1);
3302         if (!NT_STATUS_IS_OK(status)) {
3303                 printf("cli_cli_nt_delete_on_close set for directory "
3304                         "%s returned %s\n",
3305                         dname,
3306                         nt_errstr(status));
3307                 goto out;
3308         }
3309
3310         /* Create file inside target directory. */
3311         /*
3312          * NB. On Windows this will return NT_STATUS_DELETE_PENDING.  Only on
3313          * Samba will this succeed by default (the option "check parent
3314          * directory delete on close" configures behaviour), but we're using
3315          * this to test a race condition.
3316          */
3317         status = cli_ntcreate(cli,
3318                                 fname,
3319                                 0,
3320                                 FILE_READ_DATA,
3321                                 FILE_ATTRIBUTE_NORMAL,
3322                                 FILE_SHARE_READ|
3323                                         FILE_SHARE_WRITE|
3324                                         FILE_SHARE_DELETE,
3325                                 FILE_CREATE,
3326                                 0,
3327                                 0,
3328                                 &fnum1,
3329                                 NULL);
3330         if (!NT_STATUS_IS_OK(status)) {
3331                 printf("cli_ntcreate for file %s returned %s\n",
3332                                 fname,
3333                                 nt_errstr(status));
3334                 goto out;
3335         }
3336         cli_close(cli, fnum1);
3337         fnum1 = (uint16_t)-1;
3338
3339         /* Now the close should fail. */
3340         status = cli_close(cli, fnum);
3341         if (!NT_STATUS_EQUAL(status, NT_STATUS_DIRECTORY_NOT_EMPTY)) {
3342                 printf("cli_close for directory %s returned %s\n",
3343                                 dname,
3344                                 nt_errstr(status));
3345                 goto out;
3346         }
3347
3348         ret = true;
3349
3350   out:
3351
3352         if (fnum1 != (uint16_t)-1) {
3353                 cli_close(cli, fnum1);
3354         }
3355         if (fnum != (uint16_t)-1) {
3356                 cli_nt_delete_on_close(cli, fnum, 0);
3357                 cli_close(cli, fnum);
3358         }
3359         (void)cli_unlink(cli,
3360                          fname,
3361                          FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
3362         (void)cli_rmdir(cli, dname);
3363         return ret;
3364 }
3365
3366 static NTSTATUS check_empty_fn(struct file_info *finfo,
3367                                 const char *mask,
3368                                 void *private_data)
3369 {
3370         unsigned int *pcount = (unsigned int *)private_data;
3371
3372         if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
3373                 (*pcount)++;
3374                 return NT_STATUS_OK;
3375         }
3376         return NT_STATUS_DIRECTORY_NOT_EMPTY;
3377 }
3378
3379 /*
3380  * Test setting the delete on close bit on a directory
3381  * containing an unwritable file fails or succeeds
3382  * an a share set with "hide unwritable = yes"
3383  * depending on the setting of "delete veto files".
3384  * BUG: https://bugzilla.samba.org/show_bug.cgi?id=15023
3385  *
3386  * First version. With "delete veto files = yes"
3387  * setting the delete on close should succeed.
3388  */
3389
3390 bool run_delete_on_close_nonwrite_delete_yes_test(int dummy)
3391 {
3392         struct cli_state *cli = NULL;
3393         NTSTATUS status;
3394         const char *dname = "delete_veto_yes";
3395         const char *list_dname = "delete_veto_yes\\*";
3396         uint16_t fnum = (uint16_t)-1;
3397         bool ret = false;
3398         unsigned int list_count = 0;
3399
3400         printf("SMB2 delete on close nonwrite - delete veto yes\n");
3401
3402         if (!torture_init_connection(&cli)) {
3403                 return false;
3404         }
3405
3406         status = smbXcli_negprot(cli->conn,
3407                                 cli->timeout,
3408                                 PROTOCOL_SMB2_02,
3409                                 PROTOCOL_SMB3_11);
3410         if (!NT_STATUS_IS_OK(status)) {
3411                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
3412                 return false;
3413         }
3414
3415         status = cli_session_setup_creds(cli, torture_creds);
3416         if (!NT_STATUS_IS_OK(status)) {
3417                 printf("cli_session_setup returned %s\n", nt_errstr(status));
3418                 return false;
3419         }
3420
3421         status = cli_tree_connect(cli, share, "?????", NULL);
3422         if (!NT_STATUS_IS_OK(status)) {
3423                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
3424                 return false;
3425         }
3426
3427         /* Ensure target directory is seen as empty. */
3428         status = cli_list(cli,
3429                         list_dname,
3430                         FILE_ATTRIBUTE_DIRECTORY |
3431                                 FILE_ATTRIBUTE_HIDDEN |
3432                                 FILE_ATTRIBUTE_SYSTEM,
3433                         check_empty_fn,
3434                         &list_count);
3435         if (!NT_STATUS_IS_OK(status)) {
3436                 printf("cli_list of %s returned %s\n",
3437                         dname,
3438                         nt_errstr(status));
3439                 return false;
3440         }
3441         if (list_count != 2) {
3442                 printf("cli_list of %s returned a count of %u\n",
3443                         dname,
3444                         list_count);
3445                 return false;
3446         }
3447
3448         /* Open target directory. */
3449         status = cli_ntcreate(cli,
3450                                 dname,
3451                                 0,
3452                                 DELETE_ACCESS|FILE_READ_DATA,
3453                                 FILE_ATTRIBUTE_DIRECTORY,
3454                                 FILE_SHARE_READ|
3455                                         FILE_SHARE_WRITE|
3456                                         FILE_SHARE_DELETE,
3457                                 FILE_OPEN,
3458                                 FILE_DIRECTORY_FILE,
3459                                 0,
3460                                 &fnum,
3461                                 NULL);
3462         if (!NT_STATUS_IS_OK(status)) {
3463                 printf("cli_ntcreate for directory %s returned %s\n",
3464                                 dname,
3465                                 nt_errstr(status));
3466                 goto out;
3467         }
3468
3469         /* Now set the delete on close bit. */
3470         status = cli_nt_delete_on_close(cli, fnum, 1);
3471         if (!NT_STATUS_IS_OK(status)) {
3472                 printf("cli_cli_nt_delete_on_close set for directory "
3473                         "%s returned %s (should have succeeded)\n",
3474                         dname,
3475                         nt_errstr(status));
3476                 goto out;
3477         }
3478
3479         ret = true;
3480
3481   out:
3482
3483         if (fnum != (uint16_t)-1) {
3484                 (void)cli_nt_delete_on_close(cli, fnum, 0);
3485                 (void)cli_close(cli, fnum);
3486         }
3487         return ret;
3488 }
3489
3490 /*
3491  * Test setting the delete on close bit on a directory
3492  * containing an unwritable file fails or succeeds
3493  * an a share set with "hide unwritable = yes"
3494  * depending on the setting of "delete veto files".
3495  * BUG: https://bugzilla.samba.org/show_bug.cgi?id=15023
3496  *
3497  * Second version. With "delete veto files = no"
3498  * setting the delete on close should fail.
3499  */
3500
3501 bool run_delete_on_close_nonwrite_delete_no_test(int dummy)
3502 {
3503         struct cli_state *cli = NULL;
3504         NTSTATUS status;
3505         const char *dname = "delete_veto_no";
3506         const char *list_dname = "delete_veto_no\\*";
3507         uint16_t fnum = (uint16_t)-1;
3508         bool ret = false;
3509         unsigned int list_count = 0;
3510
3511         printf("SMB2 delete on close nonwrite - delete veto yes\n");
3512
3513         if (!torture_init_connection(&cli)) {
3514                 return false;
3515         }
3516
3517         status = smbXcli_negprot(cli->conn,
3518                                 cli->timeout,
3519                                 PROTOCOL_SMB2_02,
3520                                 PROTOCOL_SMB3_11);
3521         if (!NT_STATUS_IS_OK(status)) {
3522                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
3523                 return false;
3524         }
3525
3526         status = cli_session_setup_creds(cli, torture_creds);
3527         if (!NT_STATUS_IS_OK(status)) {
3528                 printf("cli_session_setup returned %s\n", nt_errstr(status));
3529                 return false;
3530         }
3531
3532         status = cli_tree_connect(cli, share, "?????", NULL);
3533         if (!NT_STATUS_IS_OK(status)) {
3534                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
3535                 return false;
3536         }
3537
3538         /* Ensure target directory is seen as empty. */
3539         status = cli_list(cli,
3540                         list_dname,
3541                         FILE_ATTRIBUTE_DIRECTORY |
3542                                 FILE_ATTRIBUTE_HIDDEN |
3543                                 FILE_ATTRIBUTE_SYSTEM,
3544                         check_empty_fn,
3545                         &list_count);
3546         if (!NT_STATUS_IS_OK(status)) {
3547                 printf("cli_list of %s returned %s\n",
3548                         dname,
3549                         nt_errstr(status));
3550                 return false;
3551         }
3552         if (list_count != 2) {
3553                 printf("cli_list of %s returned a count of %u\n",
3554                         dname,
3555                         list_count);
3556                 return false;
3557         }
3558
3559         /* Open target directory. */
3560         status = cli_ntcreate(cli,
3561                                 dname,
3562                                 0,
3563                                 DELETE_ACCESS|FILE_READ_DATA,
3564                                 FILE_ATTRIBUTE_DIRECTORY,
3565                                 FILE_SHARE_READ|
3566                                         FILE_SHARE_WRITE|
3567                                         FILE_SHARE_DELETE,
3568                                 FILE_OPEN,
3569                                 FILE_DIRECTORY_FILE,
3570                                 0,
3571                                 &fnum,
3572                                 NULL);
3573         if (!NT_STATUS_IS_OK(status)) {
3574                 printf("cli_ntcreate for directory %s returned %s\n",
3575                                 dname,
3576                                 nt_errstr(status));
3577                 goto out;
3578         }
3579
3580         /* Now set the delete on close bit. */
3581         status = cli_nt_delete_on_close(cli, fnum, 1);
3582         if (NT_STATUS_IS_OK(status)) {
3583                 printf("cli_cli_nt_delete_on_close set for directory "
3584                         "%s returned NT_STATUS_OK "
3585                         "(should have failed)\n",
3586                         dname);
3587                 goto out;
3588         }
3589         if (!NT_STATUS_EQUAL(status, NT_STATUS_DIRECTORY_NOT_EMPTY)) {
3590                 printf("cli_cli_nt_delete_on_close set for directory "
3591                         "%s returned %s "
3592                         "(should have returned "
3593                         "NT_STATUS_DIRECTORY_NOT_EMPTY)\n",
3594                         dname,
3595                         nt_errstr(status));
3596                 goto out;
3597         }
3598
3599         ret = true;
3600
3601   out:
3602
3603         if (fnum != (uint16_t)-1) {
3604                 (void)cli_nt_delete_on_close(cli, fnum, 0);
3605                 (void)cli_close(cli, fnum);
3606         }
3607         return ret;
3608 }
3609
3610 /*
3611  * Open an SMB2 file readonly and return the inode number.
3612  */
3613 static NTSTATUS get_smb2_inode(struct cli_state *cli,
3614                                 const char *pathname,
3615                                 uint64_t *ino_ret)
3616 {
3617         NTSTATUS status;
3618         uint64_t fid_persistent = 0;
3619         uint64_t fid_volatile = 0;
3620         DATA_BLOB outbuf = data_blob_null;
3621         /*
3622          * Open the file.
3623          */
3624         status = smb2cli_create(cli->conn,
3625                                 cli->timeout,
3626                                 cli->smb2.session,
3627                                 cli->smb2.tcon,
3628                                 pathname,
3629                                 SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
3630                                 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
3631                                 SEC_STD_SYNCHRONIZE|
3632                                         SEC_FILE_READ_DATA|
3633                                         SEC_FILE_READ_ATTRIBUTE, /* desired_access, */
3634                                 FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
3635                                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
3636                                 FILE_OPEN, /* create_disposition, */
3637                                 0, /* create_options, */
3638                                 NULL, /* smb2_create_blobs *blobs */
3639                                 &fid_persistent,
3640                                 &fid_volatile,
3641                                 NULL, /* struct smb_create_returns * */
3642                                 talloc_tos(), /* mem_ctx. */
3643                                 NULL); /* struct smb2_create_blobs * */
3644         if (!NT_STATUS_IS_OK(status)) {
3645                 return status;
3646         }
3647
3648         /*
3649          * Get the inode.
3650          */
3651         status = smb2cli_query_info(cli->conn,
3652                                     cli->timeout,
3653                                     cli->smb2.session,
3654                                     cli->smb2.tcon,
3655                                     SMB2_0_INFO_FILE,
3656                                     (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
3657                                     1024, /* in_max_output_length */
3658                                     NULL, /* in_input_buffer */
3659                                     0, /* in_additional_info */
3660                                     0, /* in_flags */
3661                                     fid_persistent,
3662                                     fid_volatile,
3663                                     talloc_tos(),
3664                                     &outbuf);
3665
3666         if (NT_STATUS_IS_OK(status)) {
3667                 *ino_ret = PULL_LE_U64(outbuf.data, 0x40);
3668         }
3669
3670         (void)smb2cli_close(cli->conn,
3671                             cli->timeout,
3672                             cli->smb2.session,
3673                             cli->smb2.tcon,
3674                             0,
3675                             fid_persistent,
3676                             fid_volatile);
3677         return status;
3678 }
3679
3680 /*
3681  * Check an inode matches a given SMB2 path.
3682  */
3683 static bool smb2_inode_matches(struct cli_state *cli,
3684                                 const char *match_pathname,
3685                                 uint64_t ino_tomatch,
3686                                 const char *test_pathname)
3687 {
3688         uint64_t test_ino = 0;
3689         NTSTATUS status;
3690
3691         status = get_smb2_inode(cli,
3692                                 test_pathname,
3693                                 &test_ino);
3694         if (!NT_STATUS_IS_OK(status)) {
3695                 printf("%s: Failed to get ino "
3696                         "number for %s, (%s)\n",
3697                         __func__,
3698                         test_pathname,
3699                         nt_errstr(status));
3700                 return false;
3701         }
3702         if (test_ino != ino_tomatch) {
3703                 printf("%s: Inode missmatch, ino_tomatch (%s) "
3704                         "ino=%"PRIu64" test (%s) "
3705                         "ino=%"PRIu64"\n",
3706                         __func__,
3707                         match_pathname,
3708                         ino_tomatch,
3709                         test_pathname,
3710                         test_ino);
3711                 return false;
3712         }
3713         return true;
3714 }
3715
3716 /*
3717  * Delete an SMB2 file on a DFS share.
3718  */
3719 static NTSTATUS smb2_dfs_delete(struct cli_state *cli,
3720                                 const char *pathname)
3721 {
3722         NTSTATUS status;
3723         uint64_t fid_persistent = 0;
3724         uint64_t fid_volatile = 0;
3725         uint8_t data[1];
3726         DATA_BLOB inbuf;
3727
3728         /*
3729          * Open the file.
3730          */
3731         status = smb2cli_create(cli->conn,
3732                                 cli->timeout,
3733                                 cli->smb2.session,
3734                                 cli->smb2.tcon,
3735                                 pathname,
3736                                 SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
3737                                 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
3738                                 SEC_STD_SYNCHRONIZE|
3739                                         SEC_STD_DELETE, /* desired_access, */
3740                                 FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
3741                                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
3742                                 FILE_OPEN, /* create_disposition, */
3743                                 0, /* create_options, */
3744                                 NULL, /* smb2_create_blobs *blobs */
3745                                 &fid_persistent,
3746                                 &fid_volatile,
3747                                 NULL, /* struct smb_create_returns * */
3748                                 talloc_tos(), /* mem_ctx. */
3749                                 NULL); /* struct smb2_create_blobs * */
3750         if (!NT_STATUS_IS_OK(status)) {
3751                 return status;
3752         }
3753
3754         /*
3755          * Set delete on close.
3756          */
3757         PUSH_LE_U8(&data[0], 0, 1);
3758         inbuf.data = &data[0];
3759         inbuf.length = 1;
3760
3761         status = smb2cli_set_info(cli->conn,
3762                                   cli->timeout,
3763                                   cli->smb2.session,
3764                                   cli->smb2.tcon,
3765                                   SMB2_0_INFO_FILE, /* info_type. */
3766                                   SMB_FILE_DISPOSITION_INFORMATION - 1000, /* info_class */
3767                                   &inbuf,
3768                                   0, /* additional_info. */
3769                                   fid_persistent,
3770                                   fid_volatile);
3771         if (!NT_STATUS_IS_OK(status)) {
3772                 return status;
3773         }
3774         status = smb2cli_close(cli->conn,
3775                                cli->timeout,
3776                                cli->smb2.session,
3777                                cli->smb2.tcon,
3778                                0,
3779                                fid_persistent,
3780                                fid_volatile);
3781         return status;
3782 }
3783
3784 /*
3785  * Rename or hardlink an SMB2 file on a DFS share.
3786  */
3787 static NTSTATUS smb2_dfs_setinfo_name(struct cli_state *cli,
3788                                       uint64_t fid_persistent,
3789                                       uint64_t fid_volatile,
3790                                       const char *newname,
3791                                       bool do_rename)
3792 {
3793         NTSTATUS status;
3794         DATA_BLOB inbuf;
3795         smb_ucs2_t *converted_str = NULL;
3796         size_t converted_size_bytes = 0;
3797         size_t inbuf_size;
3798         uint8_t info_class = 0;
3799         bool ok;
3800
3801         ok = push_ucs2_talloc(talloc_tos(),
3802                               &converted_str,
3803                               newname,
3804                               &converted_size_bytes);
3805         if (!ok) {
3806                 return NT_STATUS_INVALID_PARAMETER;
3807         }
3808         /*
3809          * W2K8 insists the dest name is not null terminated. Remove
3810          * the last 2 zero bytes and reduce the name length.
3811          */
3812         if (converted_size_bytes < 2) {
3813                 return NT_STATUS_INVALID_PARAMETER;
3814         }
3815         converted_size_bytes -= 2;
3816         inbuf_size = 20 + converted_size_bytes;
3817         if (inbuf_size < 20) {
3818                 /* Integer wrap check. */
3819                 return NT_STATUS_INVALID_PARAMETER;
3820         }
3821
3822         /*
3823          * The Windows 10 SMB2 server has a minimum length
3824          * for a SMB2_FILE_RENAME_INFORMATION buffer of
3825          * 24 bytes. It returns NT_STATUS_INFO_LENGTH_MISMATCH
3826          * if the length is less.
3827          */
3828         inbuf_size = MAX(inbuf_size, 24);
3829         inbuf = data_blob_talloc_zero(talloc_tos(), inbuf_size);
3830         if (inbuf.data == NULL) {
3831                 return NT_STATUS_NO_MEMORY;
3832         }
3833         PUSH_LE_U32(inbuf.data, 16, converted_size_bytes);
3834         memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
3835         TALLOC_FREE(converted_str);
3836
3837         if (do_rename == true) {
3838                 info_class = SMB_FILE_RENAME_INFORMATION - 1000;
3839         } else {
3840                 /* Hardlink. */
3841                 info_class = SMB_FILE_LINK_INFORMATION - 1000;
3842         }
3843
3844         status = smb2cli_set_info(cli->conn,
3845                                   cli->timeout,
3846                                   cli->smb2.session,
3847                                   cli->smb2.tcon,
3848                                   SMB2_0_INFO_FILE, /* info_type. */
3849                                   info_class, /* info_class */
3850                                   &inbuf,
3851                                   0, /* additional_info. */
3852                                   fid_persistent,
3853                                   fid_volatile);
3854         return status;
3855 }
3856
3857 static NTSTATUS smb2_dfs_rename(struct cli_state *cli,
3858                                       uint64_t fid_persistent,
3859                                       uint64_t fid_volatile,
3860                                       const char *newname)
3861 {
3862         return smb2_dfs_setinfo_name(cli,
3863                                      fid_persistent,
3864                                      fid_volatile,
3865                                      newname,
3866                                      true); /* do_rename */
3867 }
3868
3869 static NTSTATUS smb2_dfs_hlink(struct cli_state *cli,
3870                                uint64_t fid_persistent,
3871                                uint64_t fid_volatile,
3872                                const char *newname)
3873 {
3874         return smb2_dfs_setinfo_name(cli,
3875                                      fid_persistent,
3876                                      fid_volatile,
3877                                      newname,
3878                                      false); /* do_rename */
3879 }
3880
3881 /*
3882  * According to:
3883
3884  * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/dc9978d7-6299-4c5a-a22d-a039cdc716ea
3885  *
3886  *  (Characters " \ / [ ] : | < > + = ; , * ?,
3887  *  and control characters in range 0x00 through
3888  *  0x1F, inclusive, are illegal in a share name)
3889  *
3890  * But Windows server only checks in DFS sharenames ':'. All other
3891  * share names are allowed.
3892  */
3893
3894 static bool test_smb2_dfs_sharenames(struct cli_state *cli,
3895                                      const char *dfs_root_share_name,
3896                                      uint64_t root_ino)
3897 {
3898         char test_path[9];
3899         const char *test_str = "/[]:|<>+=;,*?";
3900         const char *p;
3901         unsigned int i;
3902         bool ino_matched = false;
3903
3904         /* Setup template pathname. */
3905         memcpy(test_path, "SERVER\\X", 9);
3906
3907         /* Test invalid control characters. */
3908         for (i = 1; i < 0x20; i++) {
3909                 test_path[7] = i;
3910                 ino_matched = smb2_inode_matches(cli,
3911                                          dfs_root_share_name,
3912                                          root_ino,
3913                                          test_path);
3914                 if (!ino_matched) {
3915                         return false;
3916                 }
3917         }
3918
3919         /* Test explicit invalid characters. */
3920         for (p = test_str; *p != '\0'; p++) {
3921                 test_path[7] = *p;
3922                 if (*p == ':') {
3923                         /*
3924                          * Only ':' is treated as an INVALID sharename
3925                          * for a DFS SERVER\\SHARE path.
3926                          */
3927                         uint64_t test_ino = 0;
3928                         NTSTATUS status = get_smb2_inode(cli,
3929                                                          test_path,
3930                                                          &test_ino);
3931                         if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_INVALID)) {
3932                                 printf("%s:%d Open of %s should get "
3933                                         "NT_STATUS_OBJECT_NAME_INVALID, got %s\n",
3934                                         __FILE__,
3935                                         __LINE__,
3936                                         test_path,
3937                                         nt_errstr(status));
3938                                 return false;
3939                         }
3940                 } else {
3941                         ino_matched = smb2_inode_matches(cli,
3942                                                  dfs_root_share_name,
3943                                                  root_ino,
3944                                                  test_path);
3945                         if (!ino_matched) {
3946                                 return false;
3947                         }
3948                 }
3949         }
3950         return true;
3951 }
3952
3953 /*
3954  * "Raw" test of SMB2 paths to a DFS share.
3955  * We must use the lower level smb2cli_XXXX() interfaces,
3956  * not the cli_XXX() ones here as the ultimate goal is to fix our
3957  * cli_XXX() interfaces to work transparently over DFS.
3958  *
3959  * So here, we're testing the server code, not the client code.
3960  *
3961  * Passes cleanly against Windows.
3962  */
3963
3964 bool run_smb2_dfs_paths(int dummy)
3965 {
3966         struct cli_state *cli = NULL;
3967         NTSTATUS status;
3968         bool dfs_supported = false;
3969         char *dfs_root_share_name = NULL;
3970         uint64_t root_ino = 0;
3971         uint64_t test_ino = 0;
3972         bool ino_matched = false;
3973         uint64_t fid_persistent = 0;
3974         uint64_t fid_volatile = 0;
3975         bool retval = false;
3976         bool ok = false;
3977
3978         printf("Starting SMB2-DFS-PATHS\n");
3979
3980         if (!torture_init_connection(&cli)) {
3981                 return false;
3982         }
3983
3984         status = smbXcli_negprot(cli->conn,
3985                                 cli->timeout,
3986                                 PROTOCOL_SMB2_02,
3987                                 PROTOCOL_SMB3_11);
3988         if (!NT_STATUS_IS_OK(status)) {
3989                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
3990                 return false;
3991         }
3992
3993         status = cli_session_setup_creds(cli, torture_creds);
3994         if (!NT_STATUS_IS_OK(status)) {
3995                 printf("cli_session_setup returned %s\n", nt_errstr(status));
3996                 return false;
3997         }
3998
3999         status = cli_tree_connect(cli, share, "?????", NULL);
4000         if (!NT_STATUS_IS_OK(status)) {
4001                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
4002                 return false;
4003         }
4004
4005         /* Ensure this is a DFS share. */
4006         dfs_supported = smbXcli_conn_dfs_supported(cli->conn);
4007         if (!dfs_supported) {
4008                 printf("Server %s does not support DFS\n",
4009                         smbXcli_conn_remote_name(cli->conn));
4010                 return false;
4011         }
4012         dfs_supported = smbXcli_tcon_is_dfs_share(cli->smb2.tcon);
4013         if (!dfs_supported) {
4014                 printf("Share %s does not support DFS\n",
4015                         cli->share);
4016                 return false;
4017         }
4018         /*
4019          * Create the "official" DFS share root name.
4020          * No SMB2 paths can start with '\\'.
4021          */
4022         dfs_root_share_name = talloc_asprintf(talloc_tos(),
4023                                         "%s\\%s",
4024                                         smbXcli_conn_remote_name(cli->conn),
4025                                         cli->share);
4026         if (dfs_root_share_name == NULL) {
4027                 printf("Out of memory\n");
4028                 return false;
4029         }
4030
4031         /* Get the share root inode number. */
4032         status = get_smb2_inode(cli,
4033                                 dfs_root_share_name,
4034                                 &root_ino);
4035         if (!NT_STATUS_IS_OK(status)) {
4036                 printf("%s:%d Failed to get ino number for share root %s, (%s)\n",
4037                         __FILE__,
4038                         __LINE__,
4039                         dfs_root_share_name,
4040                         nt_errstr(status));
4041                 return false;
4042         }
4043
4044         /*
4045          * Test the Windows algorithm for parsing DFS names.
4046          */
4047         /*
4048          * A single "SERVER" element should open and match the share root.
4049          */
4050         ino_matched = smb2_inode_matches(cli,
4051                                          dfs_root_share_name,
4052                                          root_ino,
4053                                          smbXcli_conn_remote_name(cli->conn));
4054         if (!ino_matched) {
4055                 printf("%s:%d Failed to match ino number for %s\n",
4056                         __FILE__,
4057                         __LINE__,
4058                         smbXcli_conn_remote_name(cli->conn));
4059                 return false;
4060         }
4061
4062         /*
4063          * An "" DFS empty server name should open and match the share root on
4064          * Windows 2008. Windows 2022 returns NT_STATUS_INVALID_PARAMETER
4065          * for a DFS empty server name.
4066          */
4067         status = get_smb2_inode(cli,
4068                                 "",
4069                                 &test_ino);
4070         if (NT_STATUS_IS_OK(status)) {
4071                 /*
4072                  * Windows 2008 - open succeeded. Proceed to
4073                  * check ino number.
4074                  */
4075                 ino_matched = smb2_inode_matches(cli,
4076                                                  dfs_root_share_name,
4077                                                  root_ino,
4078                                                  "");
4079                 if (!ino_matched) {
4080                         printf("%s:%d Failed to match ino number for %s\n",
4081                                 __FILE__,
4082                                 __LINE__,
4083                                 "");
4084                         return false;
4085                 }
4086         }
4087         if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
4088                 /*
4089                  * For Windows 2022 we expect to fail with
4090                  * NT_STATUS_INVALID_PARAMETER. Anything else is
4091                  * unexpected.
4092                  */
4093                 printf("%s:%d Unexpected error (%s) getting ino number for %s\n",
4094                         __FILE__,
4095                         __LINE__,
4096                         nt_errstr(status),
4097                         "");
4098                 return false;
4099         }
4100         /* A "BAD" server name should open and match the share root. */
4101         ino_matched = smb2_inode_matches(cli,
4102                                          dfs_root_share_name,
4103                                          root_ino,
4104                                          "BAD");
4105         if (!ino_matched) {
4106                 printf("%s:%d Failed to match ino number for %s\n",
4107                         __FILE__,
4108                         __LINE__,
4109                         "BAD");
4110                 return false;
4111         }
4112         /*
4113          * A "BAD\\BAD" server and share name should open
4114          * and match the share root.
4115          */
4116         ino_matched = smb2_inode_matches(cli,
4117                                          dfs_root_share_name,
4118                                          root_ino,
4119                                          "BAD\\BAD");
4120         if (!ino_matched) {
4121                 printf("%s:%d Failed to match ino number for %s\n",
4122                         __FILE__,
4123                         __LINE__,
4124                         "BAD\\BAD");
4125                 return false;
4126         }
4127         /*
4128          * Trying to open "BAD\\BAD\\BAD" should get
4129          * NT_STATUS_OBJECT_NAME_NOT_FOUND.
4130          */
4131         status = get_smb2_inode(cli,
4132                                 "BAD\\BAD\\BAD",
4133                                 &test_ino);
4134         if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
4135                 printf("%s:%d Open of %s should get "
4136                         "STATUS_OBJECT_NAME_NOT_FOUND, got %s\n",
4137                         __FILE__,
4138                         __LINE__,
4139                         "BAD\\BAD\\BAD",
4140                         nt_errstr(status));
4141                 return false;
4142         }
4143         /*
4144          * Trying to open "BAD\\BAD\\BAD\\BAD" should get
4145          * NT_STATUS_OBJECT_PATH_NOT_FOUND.
4146          */
4147         status = get_smb2_inode(cli,
4148                                 "BAD\\BAD\\BAD\\BAD",
4149                                 &test_ino);
4150         if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
4151                 printf("%s:%d Open of %s should get "
4152                         "STATUS_OBJECT_NAME_NOT_FOUND, got %s\n",
4153                         __FILE__,
4154                         __LINE__,
4155                         "BAD\\BAD\\BAD\\BAD",
4156                         nt_errstr(status));
4157                 return false;
4158         }
4159         /*
4160          * Test for invalid pathname characters in the servername.
4161          * They are ignored, and it still opens the share root.
4162          */
4163         ino_matched = smb2_inode_matches(cli,
4164                                          dfs_root_share_name,
4165                                          root_ino,
4166                                          "::::");
4167         if (!ino_matched) {
4168                 printf("%s:%d Failed to match ino number for %s\n",
4169                         __FILE__,
4170                         __LINE__,
4171                         "::::");
4172                 return false;
4173         }
4174
4175         /*
4176          * Test for invalid pathname characters in the sharename.
4177          * Invalid sharename characters should still be flagged as
4178          * NT_STATUS_OBJECT_NAME_INVALID. It turns out only ':'
4179          * is considered an invalid sharename character.
4180          */
4181         ok = test_smb2_dfs_sharenames(cli,
4182                                       dfs_root_share_name,
4183                                       root_ino);
4184         if (!ok) {
4185                 return false;
4186         }
4187
4188         /* Now create a file called "file". */
4189         status = smb2cli_create(cli->conn,
4190                                 cli->timeout,
4191                                 cli->smb2.session,
4192                                 cli->smb2.tcon,
4193                                 "BAD\\BAD\\file",
4194                                 SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
4195                                 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
4196                                 SEC_STD_SYNCHRONIZE|
4197                                         SEC_STD_DELETE |
4198                                         SEC_FILE_READ_DATA|
4199                                         SEC_FILE_READ_ATTRIBUTE, /* desired_access, */
4200                                 FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
4201                                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
4202                                 FILE_CREATE, /* create_disposition, */
4203                                 0, /* create_options, */
4204                                 NULL, /* smb2_create_blobs *blobs */
4205                                 &fid_persistent,
4206                                 &fid_volatile,
4207                                 NULL, /* struct smb_create_returns * */
4208                                 talloc_tos(), /* mem_ctx. */
4209                                 NULL); /* struct smb2_create_blobs * */
4210         if (!NT_STATUS_IS_OK(status)) {
4211                 printf("%s:%d smb2cli_create on %s returned %s\n",
4212                         __FILE__,
4213                         __LINE__,
4214                         "BAD\\BAD\\file",
4215                         nt_errstr(status));
4216                 return false;
4217         }
4218
4219         /*
4220          * Trying to open "BAD\\BAD\\file" should now get
4221          * a valid inode.
4222          */
4223         status = get_smb2_inode(cli,
4224                                 "BAD\\BAD\\file",
4225                                 &test_ino);
4226         if (!NT_STATUS_IS_OK(status)) {
4227                 printf("%s:%d Open of %s should succeed "
4228                         "got %s\n",
4229                         __FILE__,
4230                         __LINE__,
4231                         "BAD\\BAD\\file",
4232                         nt_errstr(status));
4233                 goto err;
4234         }
4235
4236         /*
4237          * Now show that renames use relative,
4238          * not full DFS paths.
4239          */
4240
4241         /* Full DFS path should fail. */
4242         status = smb2_dfs_rename(cli,
4243                                  fid_persistent,
4244                                  fid_volatile,
4245                                  "ANY\\NAME\\renamed_file");
4246         if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
4247                 printf("%s:%d Rename of %s -> %s should fail "
4248                         "with NT_STATUS_OBJECT_PATH_NOT_FOUND. Got %s\n",
4249                         __FILE__,
4250                         __LINE__,
4251                         "BAD\\BAD\\file",
4252                         "ANY\\NAME\\renamed_file",
4253                         nt_errstr(status));
4254                 goto err;
4255         }
4256         /* Relative DFS path should succeed. */
4257         status = smb2_dfs_rename(cli,
4258                                  fid_persistent,
4259                                  fid_volatile,
4260                                  "renamed_file");
4261         if (!NT_STATUS_IS_OK(status)) {
4262                 printf("%s:%d: Rename of %s -> %s should succeed. "
4263                         "Got %s\n",
4264                         __FILE__,
4265                         __LINE__,
4266                         "BAD\\BAD\\file",
4267                         "renamed_file",
4268                         nt_errstr(status));
4269                 goto err;
4270         }
4271
4272         /*
4273          * Trying to open "BAD\\BAD\\renamed_file" should now get
4274          * a valid inode.
4275          */
4276         status = get_smb2_inode(cli,
4277                                 "BAD\\BAD\\renamed_file",
4278                                 &test_ino);
4279         if (!NT_STATUS_IS_OK(status)) {
4280                 printf("%s:%d: Open of %s should succeed "
4281                         "got %s\n",
4282                         __FILE__,
4283                         __LINE__,
4284                         "BAD\\BAD\\renamed_file",
4285                         nt_errstr(status));
4286                 goto err;
4287         }
4288
4289         /*
4290          * Now show that hard links use relative,
4291          * not full DFS paths.
4292          */
4293
4294         /* Full DFS path should fail. */
4295         status = smb2_dfs_hlink(cli,
4296                                  fid_persistent,
4297                                  fid_volatile,
4298                                  "ANY\\NAME\\hlink");
4299         if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
4300                 printf("%s:%d Hlink of %s -> %s should fail "
4301                         "with NT_STATUS_OBJECT_PATH_NOT_FOUND. Got %s\n",
4302                         __FILE__,
4303                         __LINE__,
4304                         "ANY\\NAME\\renamed_file",
4305                         "ANY\\NAME\\hlink",
4306                         nt_errstr(status));
4307                 goto err;
4308         }
4309         /* Relative DFS path should succeed. */
4310         status = smb2_dfs_hlink(cli,
4311                                  fid_persistent,
4312                                  fid_volatile,
4313                                  "hlink");
4314         if (!NT_STATUS_IS_OK(status)) {
4315                 printf("%s:%d: Hlink of %s -> %s should succeed. "
4316                         "Got %s\n",
4317                         __FILE__,
4318                         __LINE__,
4319                         "ANY\\NAME\\renamed_file",
4320                         "hlink",
4321                         nt_errstr(status));
4322                 goto err;
4323         }
4324
4325         /*
4326          * Trying to open "BAD\\BAD\\hlink" should now get
4327          * a valid inode.
4328          */
4329         status = get_smb2_inode(cli,
4330                                 "BAD\\BAD\\hlink",
4331                                 &test_ino);
4332         if (!NT_STATUS_IS_OK(status)) {
4333                 printf("%s:%d Open of %s should succeed "
4334                         "got %s\n",
4335                         __FILE__,
4336                         __LINE__,
4337                         "BAD\\BAD\\hlink",
4338                         nt_errstr(status));
4339                 goto err;
4340         }
4341
4342         retval = true;
4343
4344   err:
4345
4346         if (fid_persistent != 0 || fid_volatile != 0) {
4347                 smb2cli_close(cli->conn,
4348                               cli->timeout,
4349                               cli->smb2.session,
4350                               cli->smb2.tcon,
4351                               0, /* flags */
4352                               fid_persistent,
4353                               fid_volatile);
4354         }
4355         /* Delete anything we made. */
4356         (void)smb2_dfs_delete(cli, "BAD\\BAD\\BAD");
4357         (void)smb2_dfs_delete(cli, "BAD\\BAD\\file");
4358         (void)smb2_dfs_delete(cli, "BAD\\BAD\\renamed_file");
4359         (void)smb2_dfs_delete(cli, "BAD\\BAD\\hlink");
4360         return retval;
4361 }
4362
4363 /*
4364  * Add a test that sends DFS paths and sets the
4365  * SMB2 flag FLAGS2_DFS_PATHNAMES, but to a non-DFS
4366  * share. Windows passes this (it just treats the
4367  * pathnames as non-DFS and ignores the FLAGS2_DFS_PATHNAMES
4368  * bit).
4369  */
4370
4371 bool run_smb2_non_dfs_share(int dummy)
4372 {
4373         struct cli_state *cli = NULL;
4374         NTSTATUS status;
4375         bool dfs_supported = false;
4376         uint64_t fid_persistent = 0;
4377         uint64_t fid_volatile = 0;
4378         bool retval = false;
4379         char *dfs_filename = NULL;
4380
4381         printf("Starting SMB2-DFS-NON-DFS-SHARE\n");
4382
4383         if (!torture_init_connection(&cli)) {
4384                 return false;
4385         }
4386
4387         status = smbXcli_negprot(cli->conn,
4388                                 cli->timeout,
4389                                 PROTOCOL_SMB2_02,
4390                                 PROTOCOL_SMB3_11);
4391         if (!NT_STATUS_IS_OK(status)) {
4392                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
4393                 return false;
4394         }
4395
4396         status = cli_session_setup_creds(cli, torture_creds);
4397         if (!NT_STATUS_IS_OK(status)) {
4398                 printf("cli_session_setup returned %s\n", nt_errstr(status));
4399                 return false;
4400         }
4401
4402         status = cli_tree_connect(cli, share, "?????", NULL);
4403         if (!NT_STATUS_IS_OK(status)) {
4404                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
4405                 return false;
4406         }
4407
4408         dfs_supported = smbXcli_conn_dfs_supported(cli->conn);
4409         if (!dfs_supported) {
4410                 printf("Server %s does not support DFS\n",
4411                         smbXcli_conn_remote_name(cli->conn));
4412                 return false;
4413         }
4414         /* Ensure this is *NOT* a DFS share. */
4415         dfs_supported = smbXcli_tcon_is_dfs_share(cli->smb2.tcon);
4416         if (dfs_supported) {
4417                 printf("Share %s is a DFS share.\n",
4418                         cli->share);
4419                 return false;
4420         }
4421         /*
4422          * Force the share to be DFS, as far as the client
4423          * is concerned.
4424          */
4425         smb2cli_tcon_set_values(cli->smb2.tcon,
4426                                 cli->smb2.session,
4427                                 smb2cli_tcon_current_id(cli->smb2.tcon),
4428                                 0,
4429                                 smb2cli_tcon_flags(cli->smb2.tcon),
4430                                 smb2cli_tcon_capabilities(cli->smb2.tcon) |
4431                                         SMB2_SHARE_CAP_DFS,
4432                                 0);
4433
4434         /* Come up with a "valid" SMB2 DFS name. */
4435         dfs_filename = talloc_asprintf(talloc_tos(),
4436                                        "%s\\%s\\file",
4437                                        smbXcli_conn_remote_name(cli->conn),
4438                                        cli->share);
4439         if (dfs_filename == NULL) {
4440                 printf("Out of memory\n");
4441                 return false;
4442         }
4443
4444         /* Now try create dfs_filename. */
4445         status = smb2cli_create(cli->conn,
4446                                 cli->timeout,
4447                                 cli->smb2.session,
4448                                 cli->smb2.tcon,
4449                                 dfs_filename,
4450                                 SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
4451                                 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
4452                                 SEC_STD_SYNCHRONIZE|
4453                                         SEC_STD_DELETE |
4454                                         SEC_FILE_READ_DATA|
4455                                         SEC_FILE_READ_ATTRIBUTE, /* desired_access, */
4456                                 FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
4457                                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
4458                                 FILE_CREATE, /* create_disposition, */
4459                                 0, /* create_options, */
4460                                 NULL, /* smb2_create_blobs *blobs */
4461                                 &fid_persistent,
4462                                 &fid_volatile,
4463                                 NULL, /* struct smb_create_returns * */
4464                                 talloc_tos(), /* mem_ctx. */
4465                                 NULL); /* struct smb2_create_blobs * */
4466         /*
4467          * Should fail with NT_STATUS_OBJECT_PATH_NOT_FOUND, as
4468          * even though we set the FLAGS2_DFS_PATHNAMES the server
4469          * knows this isn't a DFS share and so treats BAD\\BAD as
4470          * part of the filename.
4471          */
4472         if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
4473                 printf("%s:%d create of %s should fail "
4474                         "with NT_STATUS_OBJECT_PATH_NOT_FOUND. Got %s\n",
4475                         __FILE__,
4476                         __LINE__,
4477                         dfs_filename,
4478                         nt_errstr(status));
4479                 goto err;
4480         }
4481         /*
4482          * Prove we can still use non-DFS pathnames, even though
4483          * we are setting the FLAGS2_DFS_PATHNAMES in the SMB2
4484          * request.
4485          */
4486         status = smb2cli_create(cli->conn,
4487                                 cli->timeout,
4488                                 cli->smb2.session,
4489                                 cli->smb2.tcon,
4490                                 "file",
4491                                 SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
4492                                 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
4493                                 SEC_STD_SYNCHRONIZE|
4494                                         SEC_STD_DELETE |
4495                                         SEC_FILE_READ_DATA|
4496                                         SEC_FILE_READ_ATTRIBUTE, /* desired_access, */
4497                                 FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
4498                                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
4499                                 FILE_CREATE, /* create_disposition, */
4500                                 0, /* create_options, */
4501                                 NULL, /* smb2_create_blobs *blobs */
4502                                 &fid_persistent,
4503                                 &fid_volatile,
4504                                 NULL, /* struct smb_create_returns * */
4505                                 talloc_tos(), /* mem_ctx. */
4506                                 NULL); /* struct smb2_create_blobs * */
4507         if (!NT_STATUS_IS_OK(status)) {
4508                 printf("%s:%d smb2cli_create on %s returned %s\n",
4509                         __FILE__,
4510                         __LINE__,
4511                         "file",
4512                         nt_errstr(status));
4513                 return false;
4514         }
4515
4516         retval = true;
4517
4518   err:
4519
4520         (void)smb2_dfs_delete(cli, dfs_filename);
4521         (void)smb2_dfs_delete(cli, "file");
4522         return retval;
4523 }
4524
4525 /*
4526  * Add a test that sends a non-DFS path and does not set the
4527  * SMB2 flag FLAGS2_DFS_PATHNAMES to a DFS
4528  * share. Windows passes this (it just treats the
4529  * pathnames as non-DFS).
4530  */
4531
4532 bool run_smb2_dfs_share_non_dfs_path(int dummy)
4533 {
4534         struct cli_state *cli = NULL;
4535         NTSTATUS status;
4536         bool dfs_supported = false;
4537         uint64_t fid_persistent = 0;
4538         uint64_t fid_volatile = 0;
4539         bool retval = false;
4540         char *dfs_filename = NULL;
4541         uint64_t root_ino = (uint64_t)-1;
4542         bool ino_matched = false;
4543
4544         printf("Starting SMB2-DFS-SHARE-NON-DFS-PATH\n");
4545
4546         if (!torture_init_connection(&cli)) {
4547                 return false;
4548         }
4549
4550         status = smbXcli_negprot(cli->conn,
4551                                 cli->timeout,
4552                                 PROTOCOL_SMB2_02,
4553                                 PROTOCOL_SMB3_11);
4554         if (!NT_STATUS_IS_OK(status)) {
4555                 printf("smbXcli_negprot returned %s\n", nt_errstr(status));
4556                 return false;
4557         }
4558
4559         status = cli_session_setup_creds(cli, torture_creds);
4560         if (!NT_STATUS_IS_OK(status)) {
4561                 printf("cli_session_setup returned %s\n", nt_errstr(status));
4562                 return false;
4563         }
4564
4565         status = cli_tree_connect(cli, share, "?????", NULL);
4566         if (!NT_STATUS_IS_OK(status)) {
4567                 printf("cli_tree_connect returned %s\n", nt_errstr(status));
4568                 return false;
4569         }
4570
4571         dfs_supported = smbXcli_conn_dfs_supported(cli->conn);
4572         if (!dfs_supported) {
4573                 printf("Server %s does not support DFS\n",
4574                         smbXcli_conn_remote_name(cli->conn));
4575                 return false;
4576         }
4577         /* Ensure this is a DFS share. */
4578         dfs_supported = smbXcli_tcon_is_dfs_share(cli->smb2.tcon);
4579         if (!dfs_supported) {
4580                 printf("Share %s is not a DFS share.\n",
4581                         cli->share);
4582                 return false;
4583         }
4584         /* Come up with a "valid" SMB2 DFS name. */
4585         dfs_filename = talloc_asprintf(talloc_tos(),
4586                                        "%s\\%s\\file",
4587                                        smbXcli_conn_remote_name(cli->conn),
4588                                        cli->share);
4589         if (dfs_filename == NULL) {
4590                 printf("Out of memory\n");
4591                 return false;
4592         }
4593
4594         /* Get the root of the share ino. */
4595         status = get_smb2_inode(cli,
4596                                 "SERVER\\SHARE",
4597                                 &root_ino);
4598         if (!NT_STATUS_IS_OK(status)) {
4599                 printf("%s:%d get_smb2_inode on %s returned %s\n",
4600                         __FILE__,
4601                         __LINE__,
4602                         "SERVER\\SHARE",
4603                         nt_errstr(status));
4604                 goto err;
4605         }
4606
4607         /* Create a dfs_filename. */
4608         status = smb2cli_create(cli->conn,
4609                                 cli->timeout,
4610                                 cli->smb2.session,
4611                                 cli->smb2.tcon,
4612                                 dfs_filename,
4613                                 SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
4614                                 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
4615                                 SEC_STD_SYNCHRONIZE|
4616                                         SEC_STD_DELETE |
4617                                         SEC_FILE_READ_DATA|
4618                                         SEC_FILE_READ_ATTRIBUTE, /* desired_access, */
4619                                 FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
4620                                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
4621                                 FILE_CREATE, /* create_disposition, */
4622                                 0, /* create_options, */
4623                                 NULL, /* smb2_create_blobs *blobs */
4624                                 &fid_persistent,
4625                                 &fid_volatile,
4626                                 NULL, /* struct smb_create_returns * */
4627                                 talloc_tos(), /* mem_ctx. */
4628                                 NULL); /* struct smb2_create_blobs * */
4629         if (!NT_STATUS_IS_OK(status)) {
4630                 printf("%s:%d smb2cli_create on %s returned %s\n",
4631                         __FILE__,
4632                         __LINE__,
4633                         dfs_filename,
4634                         nt_errstr(status));
4635                 goto err;
4636         }
4637
4638         /* Close the handle we just opened. */
4639         smb2cli_close(cli->conn,
4640                       cli->timeout,
4641                       cli->smb2.session,
4642                       cli->smb2.tcon,
4643                       0, /* flags */
4644                       fid_persistent,
4645                       fid_volatile);
4646
4647         fid_persistent = 0;
4648         fid_volatile = 0;
4649
4650         /*
4651          * Force the share to be non-DFS, as far as the client
4652          * is concerned.
4653          */
4654         smb2cli_tcon_set_values(cli->smb2.tcon,
4655                         cli->smb2.session,
4656                         smb2cli_tcon_current_id(cli->smb2.tcon),
4657                         0,
4658                         smb2cli_tcon_flags(cli->smb2.tcon),
4659                         smb2cli_tcon_capabilities(cli->smb2.tcon) &
4660                                 ~SMB2_SHARE_CAP_DFS,
4661                         0);
4662
4663         /*
4664          * Prove we can still use non-DFS pathnames on a DFS
4665          * share so long as we don't set the FLAGS2_DFS_PATHNAMES
4666          * in the SMB2 request.
4667          */
4668         status = smb2cli_create(cli->conn,
4669                                 cli->timeout,
4670                                 cli->smb2.session,
4671                                 cli->smb2.tcon,
4672                                 "file",
4673                                 SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
4674                                 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
4675                                 SEC_STD_SYNCHRONIZE|
4676                                         SEC_STD_DELETE |
4677                                         SEC_FILE_READ_DATA|
4678                                         SEC_FILE_READ_ATTRIBUTE, /* desired_access, */
4679                                 FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
4680                                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
4681                                 FILE_OPEN, /* create_disposition, */
4682                                 0, /* create_options, */
4683                                 NULL, /* smb2_create_blobs *blobs */
4684                                 &fid_persistent,
4685                                 &fid_volatile,
4686                                 NULL, /* struct smb_create_returns * */
4687                                 talloc_tos(), /* mem_ctx. */
4688                                 NULL); /* struct smb2_create_blobs * */
4689         if (!NT_STATUS_IS_OK(status)) {
4690                 printf("%s:%d smb2cli_create on %s returned %s\n",
4691                         __FILE__,
4692                         __LINE__,
4693                         "file",
4694                         nt_errstr(status));
4695                 goto err;
4696         }
4697
4698         /*
4699          * Show that now we're using non-DFS pathnames
4700          * on a DFS share, "" opens the root of the share.
4701          */
4702         ino_matched = smb2_inode_matches(cli,
4703                                          "SERVER\\SHARE",
4704                                          root_ino,
4705                                          "");
4706         if (!ino_matched) {
4707                 printf("%s:%d Failed to match ino number for %s\n",
4708                         __FILE__,
4709                         __LINE__,
4710                         "");
4711                 goto err;
4712         }
4713
4714         retval = true;
4715
4716   err:
4717
4718         if (fid_volatile != 0) {
4719                 smb2cli_close(cli->conn,
4720                               cli->timeout,
4721                               cli->smb2.session,
4722                               cli->smb2.tcon,
4723                               0, /* flags */
4724                               fid_persistent,
4725                               fid_volatile);
4726         }
4727         (void)smb2_dfs_delete(cli, "file");
4728         (void)smb2_dfs_delete(cli, dfs_filename);
4729         return retval;
4730 }