s3:libsmb: pass impersonation_level to cli_ntcreate_send()
[metze/samba/wip.git] / source3 / torture / test_chain3.c
1 /*
2    Unix SMB/CIFS implementation.
3    Test smbd chain routines
4
5    Copyright (C) Volker Lendecke 2012
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "torture/proto.h"
23 #include "libsmb/libsmb.h"
24 #include "system/filesys.h"
25 #include "async_smb.h"
26 #include "lib/util/tevent_ntstatus.h"
27 #include "libcli/security/security.h"
28 #include "libcli/smb/smbXcli_base.h"
29
30 struct chain3_andx_state {
31         uint16_t fnum;
32         size_t written;
33         char str[6];
34 };
35
36 static void chain3_andx_open_done(struct tevent_req *subreq);
37 static void chain3_andx_write_done(struct tevent_req *subreq);
38 static void chain3_andx_close_done(struct tevent_req *subreq);
39
40 static struct tevent_req *chain3_andx_send(TALLOC_CTX *mem_ctx,
41                                            struct tevent_context *ev,
42                                            struct cli_state *cli,
43                                            const char *fname)
44 {
45         struct tevent_req *req, *subreq;
46         struct tevent_req *smbreqs[3];
47         struct chain3_andx_state *state;
48         NTSTATUS status;
49
50         req = tevent_req_create(mem_ctx, &state, struct chain3_andx_state);
51         if (req == NULL) {
52                 return NULL;
53         }
54
55         strlcpy(state->str, "hello", sizeof(state->str));
56
57         subreq = cli_openx_create(state, ev, cli, fname,
58                                   O_CREAT|O_RDWR, 0, &smbreqs[0]);
59         if (tevent_req_nomem(subreq, req)) {
60                 return tevent_req_post(req, ev);
61         }
62         tevent_req_set_callback(subreq, chain3_andx_open_done, req);
63
64         subreq = cli_write_andx_create(state, ev, cli, 0, 0,
65                                        (const uint8_t *)state->str, 0,
66                                        strlen(state->str)+1,
67                                        smbreqs, 1, &smbreqs[1]);
68         if (tevent_req_nomem(subreq, req)) {
69                 return tevent_req_post(req, ev);
70         }
71         tevent_req_set_callback(subreq, chain3_andx_write_done, req);
72
73         subreq = cli_smb1_close_create(state, ev, cli, 0, &smbreqs[2]);
74         if (tevent_req_nomem(subreq, req)) {
75                 return tevent_req_post(req, ev);
76         }
77         tevent_req_set_callback(subreq, chain3_andx_close_done, req);
78
79         status = smb1cli_req_chain_submit(smbreqs, ARRAY_SIZE(smbreqs));
80         if (tevent_req_nterror(req, status)) {
81                 return tevent_req_post(req, ev);
82         }
83         return req;
84 }
85
86 static void chain3_andx_open_done(struct tevent_req *subreq)
87 {
88         struct tevent_req *req = tevent_req_callback_data(
89                 subreq, struct tevent_req);
90         struct chain3_andx_state *state = tevent_req_data(
91                 req, struct chain3_andx_state);
92         NTSTATUS status;
93
94         status = cli_openx_recv(subreq, &state->fnum);
95         printf("cli_openx returned %s, fnum=%u\n", nt_errstr(status),
96                (unsigned)state->fnum);
97         TALLOC_FREE(subreq);
98         if (tevent_req_nterror(req, status)) {
99                 return;
100         }
101 }
102
103 static void chain3_andx_write_done(struct tevent_req *subreq)
104 {
105         struct tevent_req *req = tevent_req_callback_data(
106                 subreq, struct tevent_req);
107         struct chain3_andx_state *state = tevent_req_data(
108                 req, struct chain3_andx_state);
109         NTSTATUS status;
110
111         status = cli_write_andx_recv(subreq, &state->written);
112         printf("cli_write_andx returned %s, written=%u\n", nt_errstr(status),
113                (unsigned)state->written);
114         TALLOC_FREE(subreq);
115         if (tevent_req_nterror(req, status)) {
116                 return;
117         }
118 }
119
120 static void chain3_andx_close_done(struct tevent_req *subreq)
121 {
122         struct tevent_req *req = tevent_req_callback_data(
123                 subreq, struct tevent_req);
124         NTSTATUS status;
125
126         status = cli_close_recv(subreq);
127         printf("cli_close returned %s\n", nt_errstr(status));
128         TALLOC_FREE(subreq);
129         if (tevent_req_nterror(req, status)) {
130                 return;
131         }
132         tevent_req_done(req);
133 }
134
135 static NTSTATUS chain3_andx_recv(struct tevent_req *req)
136 {
137         return tevent_req_simple_recv_ntstatus(req);
138 }
139
140 struct chain3_state {
141         struct tevent_context *ev;
142         struct cli_state *cli;
143         const char *fname;
144         uint16_t fnum;
145 };
146
147 static void chain3_got_break(struct tevent_req *subreq);
148 static void chain3_ntcreate_done(struct tevent_req *subreq);
149 static void chain3_break_close_done(struct tevent_req *subreq);
150 static void chain3_andx_done(struct tevent_req *subreq);
151
152 static struct tevent_req *chain3_send(TALLOC_CTX *mem_ctx,
153                                       struct tevent_context *ev)
154 {
155         struct tevent_req *req, *subreq;
156         struct chain3_state *state;
157
158         req = tevent_req_create(mem_ctx, &state, struct chain3_state);
159         if (req == NULL) {
160                 return NULL;
161         }
162         state->ev = ev;
163         state->fname = "chain3.txt";
164
165         if (!torture_open_connection(&state->cli, 0)) {
166                 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
167                 return tevent_req_post(req, ev);
168         }
169
170         subreq = cli_smb_oplock_break_waiter_send(
171                 state, state->ev, state->cli);
172         if (tevent_req_nomem(subreq, req)) {
173                 return tevent_req_post(req, ev);
174         }
175         tevent_req_set_callback(subreq, chain3_got_break, req);
176
177         subreq = cli_ntcreate_send(
178                 state, state->ev, state->cli, state->fname,
179                 REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK,
180                 GENERIC_READ_ACCESS|GENERIC_WRITE_ACCESS,
181                 FILE_ATTRIBUTE_NORMAL,
182                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
183                 FILE_OVERWRITE_IF, 0,
184                 SMB2_IMPERSONATION_IMPERSONATION, 0);
185         if (tevent_req_nomem(subreq, req)) {
186                 return tevent_req_post(req, ev);
187         }
188         tevent_req_set_callback(subreq, chain3_ntcreate_done, req);
189         return req;
190 }
191
192 static void chain3_got_break(struct tevent_req *subreq)
193 {
194         struct tevent_req *req = tevent_req_callback_data(
195                 subreq, struct tevent_req);
196         struct chain3_state *state = tevent_req_data(
197                 req, struct chain3_state);
198         uint16_t fnum;
199         uint8_t level;
200         NTSTATUS status;
201
202         status = cli_smb_oplock_break_waiter_recv(subreq, &fnum, &level);
203         TALLOC_FREE(subreq);
204         printf("cli_smb_oplock_break_waiter_recv returned %s\n",
205                nt_errstr(status));
206         if (tevent_req_nterror(req, status)) {
207                 return;
208         }
209         subreq = cli_close_send(state, state->ev, state->cli, fnum);
210         if (tevent_req_nomem(subreq, req)) {
211                 return;
212         }
213         tevent_req_set_callback(subreq, chain3_break_close_done, req);
214 }
215
216 static void chain3_break_close_done(struct tevent_req *subreq)
217 {
218         struct tevent_req *req = tevent_req_callback_data(
219                 subreq, struct tevent_req);
220         NTSTATUS status;
221
222         status = cli_close_recv(subreq);
223         TALLOC_FREE(subreq);
224         printf("cli_close_recv returned %s\n", nt_errstr(status));
225         if (tevent_req_nterror(req, status)) {
226                 return;
227         }
228 }
229
230 static void chain3_ntcreate_done(struct tevent_req *subreq)
231 {
232         struct tevent_req *req = tevent_req_callback_data(
233                 subreq, struct tevent_req);
234         struct chain3_state *state = tevent_req_data(
235                 req, struct chain3_state);
236         NTSTATUS status;
237
238         status = cli_ntcreate_recv(subreq, &state->fnum, NULL);
239         TALLOC_FREE(subreq);
240         printf("cli_ntcreate returned %s, fnum=%u\n", nt_errstr(status),
241                (unsigned)state->fnum);
242         if (tevent_req_nterror(req, status)) {
243                 return;
244         }
245
246         subreq = chain3_andx_send(state, state->ev, state->cli, state->fname);
247         if (tevent_req_nomem(subreq, req)) {
248                 return;
249         }
250         tevent_req_set_callback(subreq, chain3_andx_done, req);
251 }
252
253 static void chain3_andx_done(struct tevent_req *subreq)
254 {
255         struct tevent_req *req = tevent_req_callback_data(
256                 subreq, struct tevent_req);
257         NTSTATUS status;
258
259         status = chain3_andx_recv(subreq);
260         TALLOC_FREE(subreq);
261         printf("chain3_andx_recv returned %s\n", nt_errstr(status));
262         if (tevent_req_nterror(req, status)) {
263                 return;
264         }
265         tevent_req_done(req);
266 }
267
268 static NTSTATUS chain3_recv(struct tevent_req *req)
269 {
270         return tevent_req_simple_recv_ntstatus(req);
271 }
272
273 bool run_chain3(int dummy)
274 {
275         TALLOC_CTX *frame = talloc_stackframe();
276         struct tevent_context *ev;
277         struct tevent_req *req;
278         NTSTATUS status = NT_STATUS_NO_MEMORY;
279
280         ev = samba_tevent_context_init(frame);
281         if (ev == NULL) {
282                 goto fail;
283         }
284         req = chain3_send(frame, ev);
285         if (req == NULL) {
286                 goto fail;
287         }
288         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
289                 goto fail;
290         }
291         status = chain3_recv(req);
292 fail:
293         TALLOC_FREE(frame);
294         printf("run_chain3 returns %s\n", nt_errstr(status));
295         return NT_STATUS_IS_OK(status);
296 }