7b9eeb0b7b38bcac20eaea4201040ae382352ec4
[kai/samba.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
29 struct chain3_andx_state {
30         uint16_t fnum;
31         size_t written;
32         char str[6];
33 };
34
35 static void chain3_andx_open_done(struct tevent_req *subreq);
36 static void chain3_andx_write_done(struct tevent_req *subreq);
37 static void chain3_andx_close_done(struct tevent_req *subreq);
38
39 static struct tevent_req *chain3_andx_send(TALLOC_CTX *mem_ctx,
40                                            struct tevent_context *ev,
41                                            struct cli_state *cli,
42                                            const char *fname)
43 {
44         struct tevent_req *req, *subreq;
45         struct tevent_req *smbreqs[3];
46         struct chain3_andx_state *state;
47         NTSTATUS status;
48
49         req = tevent_req_create(mem_ctx, &state, struct chain3_andx_state);
50         if (req == NULL) {
51                 return NULL;
52         }
53
54         strlcpy(state->str, "hello", sizeof(state->str));
55
56         subreq = cli_openx_create(state, ev, cli, fname,
57                                   O_CREAT|O_RDWR, 0, &smbreqs[0]);
58         if (tevent_req_nomem(subreq, req)) {
59                 return tevent_req_post(req, ev);
60         }
61         tevent_req_set_callback(subreq, chain3_andx_open_done, req);
62
63         subreq = cli_write_andx_create(state, ev, cli, 0, 0,
64                                        (const uint8_t *)state->str, 0,
65                                        strlen(state->str)+1,
66                                        smbreqs, 1, &smbreqs[1]);
67         if (tevent_req_nomem(subreq, req)) {
68                 return tevent_req_post(req, ev);
69         }
70         tevent_req_set_callback(subreq, chain3_andx_write_done, req);
71
72         subreq = cli_close_create(state, ev, cli, 0, &smbreqs[2]);
73         if (tevent_req_nomem(subreq, req)) {
74                 return tevent_req_post(req, ev);
75         }
76         tevent_req_set_callback(subreq, chain3_andx_close_done, req);
77
78         status = cli_smb_chain_send(smbreqs, ARRAY_SIZE(smbreqs));
79         if (tevent_req_nterror(req, status)) {
80                 return tevent_req_post(req, ev);
81         }
82         return req;
83 }
84
85 static void chain3_andx_open_done(struct tevent_req *subreq)
86 {
87         struct tevent_req *req = tevent_req_callback_data(
88                 subreq, struct tevent_req);
89         struct chain3_andx_state *state = tevent_req_data(
90                 req, struct chain3_andx_state);
91         NTSTATUS status;
92
93         status = cli_openx_recv(subreq, &state->fnum);
94         printf("cli_openx returned %s, fnum=%u\n", nt_errstr(status),
95                (unsigned)state->fnum);
96         TALLOC_FREE(subreq);
97         if (tevent_req_nterror(req, status)) {
98                 return;
99         }
100 }
101
102 static void chain3_andx_write_done(struct tevent_req *subreq)
103 {
104         struct tevent_req *req = tevent_req_callback_data(
105                 subreq, struct tevent_req);
106         struct chain3_andx_state *state = tevent_req_data(
107                 req, struct chain3_andx_state);
108         NTSTATUS status;
109
110         status = cli_write_andx_recv(subreq, &state->written);
111         printf("cli_write_andx returned %s, written=%u\n", nt_errstr(status),
112                (unsigned)state->written);
113         TALLOC_FREE(subreq);
114         if (tevent_req_nterror(req, status)) {
115                 return;
116         }
117 }
118
119 static void chain3_andx_close_done(struct tevent_req *subreq)
120 {
121         struct tevent_req *req = tevent_req_callback_data(
122                 subreq, struct tevent_req);
123         NTSTATUS status;
124
125         status = cli_close_recv(subreq);
126         printf("cli_close returned %s\n", nt_errstr(status));
127         TALLOC_FREE(subreq);
128         if (tevent_req_nterror(req, status)) {
129                 return;
130         }
131         tevent_req_done(req);
132 }
133
134 static NTSTATUS chain3_andx_recv(struct tevent_req *req)
135 {
136         return tevent_req_simple_recv_ntstatus(req);
137 }
138
139 struct chain3_state {
140         struct tevent_context *ev;
141         struct cli_state *cli;
142         const char *fname;
143         uint16_t fnum;
144 };
145
146 static void chain3_got_break(struct tevent_req *subreq);
147 static void chain3_ntcreate_done(struct tevent_req *subreq);
148 static void chain3_break_close_done(struct tevent_req *subreq);
149 static void chain3_andx_done(struct tevent_req *subreq);
150
151 static struct tevent_req *chain3_send(TALLOC_CTX *mem_ctx,
152                                       struct tevent_context *ev)
153 {
154         struct tevent_req *req, *subreq;
155         struct chain3_state *state;
156
157         req = tevent_req_create(mem_ctx, &state, struct chain3_state);
158         if (req == NULL) {
159                 return NULL;
160         }
161         state->ev = ev;
162         state->fname = "chain3.txt";
163
164         if (!torture_open_connection(&state->cli, 0)) {
165                 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
166                 return tevent_req_post(req, ev);
167         }
168
169         subreq = cli_smb_oplock_break_waiter_send(
170                 state, state->ev, state->cli);
171         if (tevent_req_nomem(subreq, req)) {
172                 return tevent_req_post(req, ev);
173         }
174         tevent_req_set_callback(subreq, chain3_got_break, req);
175
176         subreq = cli_ntcreate_send(
177                 state, state->ev, state->cli, state->fname,
178                 REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK,
179                 GENERIC_READ_ACCESS|GENERIC_WRITE_ACCESS,
180                 FILE_ATTRIBUTE_NORMAL,
181                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
182                 FILE_OVERWRITE_IF, 0, 0);
183         if (tevent_req_nomem(subreq, req)) {
184                 return tevent_req_post(req, ev);
185         }
186         tevent_req_set_callback(subreq, chain3_ntcreate_done, req);
187         return req;
188 }
189
190 static void chain3_got_break(struct tevent_req *subreq)
191 {
192         struct tevent_req *req = tevent_req_callback_data(
193                 subreq, struct tevent_req);
194         struct chain3_state *state = tevent_req_data(
195                 req, struct chain3_state);
196         uint16_t fnum;
197         uint8_t level;
198         NTSTATUS status;
199
200         status = cli_smb_oplock_break_waiter_recv(subreq, &fnum, &level);
201         TALLOC_FREE(subreq);
202         printf("cli_smb_oplock_break_waiter_recv returned %s\n",
203                nt_errstr(status));
204         if (tevent_req_nterror(req, status)) {
205                 return;
206         }
207         subreq = cli_close_send(state, state->ev, state->cli, fnum);
208         if (tevent_req_nomem(subreq, req)) {
209                 return;
210         }
211         tevent_req_set_callback(subreq, chain3_break_close_done, req);
212 }
213
214 static void chain3_break_close_done(struct tevent_req *subreq)
215 {
216         struct tevent_req *req = tevent_req_callback_data(
217                 subreq, struct tevent_req);
218         NTSTATUS status;
219
220         status = cli_close_recv(subreq);
221         TALLOC_FREE(subreq);
222         printf("cli_close_recv returned %s\n", nt_errstr(status));
223         if (tevent_req_nterror(req, status)) {
224                 return;
225         }
226 }
227
228 static void chain3_ntcreate_done(struct tevent_req *subreq)
229 {
230         struct tevent_req *req = tevent_req_callback_data(
231                 subreq, struct tevent_req);
232         struct chain3_state *state = tevent_req_data(
233                 req, struct chain3_state);
234         NTSTATUS status;
235
236         status = cli_ntcreate_recv(subreq, &state->fnum);
237         TALLOC_FREE(subreq);
238         printf("cli_ntcreate returned %s, fnum=%u\n", nt_errstr(status),
239                (unsigned)state->fnum);
240         if (tevent_req_nterror(req, status)) {
241                 return;
242         }
243
244         subreq = chain3_andx_send(state, state->ev, state->cli, state->fname);
245         if (tevent_req_nomem(subreq, req)) {
246                 return;
247         }
248         tevent_req_set_callback(subreq, chain3_andx_done, req);
249 }
250
251 static void chain3_andx_done(struct tevent_req *subreq)
252 {
253         struct tevent_req *req = tevent_req_callback_data(
254                 subreq, struct tevent_req);
255         NTSTATUS status;
256
257         status = chain3_andx_recv(subreq);
258         TALLOC_FREE(subreq);
259         printf("chain3_andx_recv returned %s\n", nt_errstr(status));
260         if (tevent_req_nterror(req, status)) {
261                 return;
262         }
263         tevent_req_done(req);
264 }
265
266 static NTSTATUS chain3_recv(struct tevent_req *req)
267 {
268         return tevent_req_simple_recv_ntstatus(req);
269 }
270
271 bool run_chain3(int dummy)
272 {
273         TALLOC_CTX *frame = talloc_stackframe();
274         struct tevent_context *ev;
275         struct tevent_req *req;
276         NTSTATUS status = NT_STATUS_NO_MEMORY;
277
278         ev = tevent_context_init(frame);
279         if (ev == NULL) {
280                 goto fail;
281         }
282         req = chain3_send(frame, ev);
283         if (req == NULL) {
284                 goto fail;
285         }
286         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
287                 goto fail;
288         }
289         status = chain3_recv(req);
290 fail:
291         TALLOC_FREE(frame);
292         printf("run_chain3 returns %s\n", nt_errstr(status));
293         return NT_STATUS_IS_OK(status);
294 }