Convert all uint32/16/8 to _t in source3/libsmb.
[bbaumbach/samba-autobuild/.git] / source3 / libsmb / climessage.c
1 /*
2    Unix SMB/CIFS implementation.
3    client message handling routines
4    Copyright (C) Andrew Tridgell 1994-1998
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 "../lib/util/tevent_ntstatus.h"
22 #include "async_smb.h"
23 #include "libsmb/libsmb.h"
24 #include "../libcli/smb/smbXcli_base.h"
25
26 struct cli_message_start_state {
27         uint16_t grp;
28 };
29
30 static void cli_message_start_done(struct tevent_req *subreq);
31
32 static struct tevent_req *cli_message_start_send(TALLOC_CTX *mem_ctx,
33                                                  struct tevent_context *ev,
34                                                  struct cli_state *cli,
35                                                  const char *host,
36                                                  const char *username)
37 {
38         struct tevent_req *req, *subreq;
39         struct cli_message_start_state *state;
40         char *htmp = NULL;
41         char *utmp = NULL;
42         size_t hlen, ulen;
43         uint8_t *bytes, *p;
44
45         req = tevent_req_create(mem_ctx, &state,
46                                 struct cli_message_start_state);
47         if (req == NULL) {
48                 return NULL;
49         }
50
51         if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
52                                    username, strlen(username)+1,
53                                    &utmp, &ulen)) {
54                 goto fail;
55         }
56         if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
57                                    host, strlen(host)+1,
58                                    &htmp, &hlen)) {
59                 goto fail;
60         }
61
62         bytes = talloc_array(state, uint8_t, ulen+hlen+2);
63         if (bytes == NULL) {
64                 goto fail;
65         }
66         p = bytes;
67
68         *p++ = 4;
69         memcpy(p, utmp, ulen);
70         p += ulen;
71         *p++ = 4;
72         memcpy(p, htmp, hlen);
73         p += hlen;
74         TALLOC_FREE(htmp);
75         TALLOC_FREE(utmp);
76
77         subreq = cli_smb_send(state, ev, cli, SMBsendstrt, 0, 0, NULL,
78                               talloc_get_size(bytes), bytes);
79         if (tevent_req_nomem(subreq, req)) {
80                 return tevent_req_post(req, ev);
81         }
82         tevent_req_set_callback(subreq, cli_message_start_done, req);
83         return req;
84 fail:
85         TALLOC_FREE(htmp);
86         TALLOC_FREE(utmp);
87         tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
88         return tevent_req_post(req, ev);
89 }
90
91 static void cli_message_start_done(struct tevent_req *subreq)
92 {
93         struct tevent_req *req = tevent_req_callback_data(
94                 subreq, struct tevent_req);
95         struct cli_message_start_state *state = tevent_req_data(
96                 req, struct cli_message_start_state);
97         NTSTATUS status;
98         uint8_t wct;
99         uint16_t *vwv;
100
101         status = cli_smb_recv(subreq, state, NULL, 0, &wct, &vwv,
102                               NULL, NULL);
103         TALLOC_FREE(subreq);
104         if (!NT_STATUS_IS_OK(status)) {
105                 TALLOC_FREE(subreq);
106                 tevent_req_nterror(req, status);
107                 return;
108         }
109         if (wct >= 1) {
110                 state->grp = SVAL(vwv+0, 0);
111         } else {
112                 state->grp = 0;
113         }
114         tevent_req_done(req);
115 }
116
117 static NTSTATUS cli_message_start_recv(struct tevent_req *req,
118                                        uint16_t *pgrp)
119 {
120         struct cli_message_start_state *state = tevent_req_data(
121                 req, struct cli_message_start_state);
122         NTSTATUS status;
123
124         if (tevent_req_is_nterror(req, &status)) {
125                 return status;
126         }
127         *pgrp = state->grp;
128         return NT_STATUS_OK;
129 }
130
131 struct cli_message_text_state {
132         uint16_t vwv;
133 };
134
135 static void cli_message_text_done(struct tevent_req *subreq);
136
137 static struct tevent_req *cli_message_text_send(TALLOC_CTX *mem_ctx,
138                                                 struct tevent_context *ev,
139                                                 struct cli_state *cli,
140                                                 uint16_t grp,
141                                                 const char *msg,
142                                                 int msglen)
143 {
144         struct tevent_req *req, *subreq;
145         struct cli_message_text_state *state;
146         char *tmp;
147         size_t tmplen;
148         uint8_t *bytes;
149
150         req = tevent_req_create(mem_ctx, &state,
151                                 struct cli_message_text_state);
152         if (req == NULL) {
153                 return NULL;
154         }
155
156         SSVAL(&state->vwv, 0, grp);
157
158         if (convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS, msg, msglen,
159                                   &tmp, &tmplen)) {
160                 msg = tmp;
161                 msglen = tmplen;
162         } else {
163                 DEBUG(3, ("Conversion failed, sending message in UNIX "
164                           "charset\n"));
165                 tmp = NULL;
166         }
167
168         bytes = talloc_array(state, uint8_t, msglen+3);
169         if (tevent_req_nomem(bytes, req)) {
170                 TALLOC_FREE(tmp);
171                 return tevent_req_post(req, ev);
172         }
173         SCVAL(bytes, 0, 1);     /* pad */
174         SSVAL(bytes+1, 0, msglen);
175         memcpy(bytes+3, msg, msglen);
176         TALLOC_FREE(tmp);
177
178         subreq = cli_smb_send(state, ev, cli, SMBsendtxt, 0, 1, &state->vwv,
179                               talloc_get_size(bytes), bytes);
180         if (tevent_req_nomem(subreq, req)) {
181                 return tevent_req_post(req, ev);
182         }
183         tevent_req_set_callback(subreq, cli_message_text_done, req);
184         return req;
185 }
186
187 static void cli_message_text_done(struct tevent_req *subreq)
188 {
189         struct tevent_req *req = tevent_req_callback_data(
190                 subreq, struct tevent_req);
191         NTSTATUS status;
192
193         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
194         TALLOC_FREE(subreq);
195         if (!NT_STATUS_IS_OK(status)) {
196                 tevent_req_nterror(req, status);
197                 return;
198         }
199         tevent_req_done(req);
200 }
201
202 static NTSTATUS cli_message_text_recv(struct tevent_req *req)
203 {
204         return tevent_req_simple_recv_ntstatus(req);
205 }
206
207 struct cli_message_end_state {
208         uint16_t vwv;
209 };
210
211 static void cli_message_end_done(struct tevent_req *subreq);
212
213 static struct tevent_req *cli_message_end_send(TALLOC_CTX *mem_ctx,
214                                                 struct tevent_context *ev,
215                                                 struct cli_state *cli,
216                                                 uint16_t grp)
217 {
218         struct tevent_req *req, *subreq;
219         struct cli_message_end_state *state;
220
221         req = tevent_req_create(mem_ctx, &state,
222                                 struct cli_message_end_state);
223         if (req == NULL) {
224                 return NULL;
225         }
226
227         SSVAL(&state->vwv, 0, grp);
228
229         subreq = cli_smb_send(state, ev, cli, SMBsendend, 0, 1, &state->vwv,
230                               0, NULL);
231         if (tevent_req_nomem(subreq, req)) {
232                 return tevent_req_post(req, ev);
233         }
234         tevent_req_set_callback(subreq, cli_message_end_done, req);
235         return req;
236 }
237
238 static void cli_message_end_done(struct tevent_req *subreq)
239 {
240         struct tevent_req *req = tevent_req_callback_data(
241                 subreq, struct tevent_req);
242         NTSTATUS status;
243
244         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
245         TALLOC_FREE(subreq);
246         if (!NT_STATUS_IS_OK(status)) {
247                 tevent_req_nterror(req, status);
248                 return;
249         }
250         tevent_req_done(req);
251 }
252
253 static NTSTATUS cli_message_end_recv(struct tevent_req *req)
254 {
255         return tevent_req_simple_recv_ntstatus(req);
256 }
257
258 struct cli_message_state {
259         struct tevent_context *ev;
260         struct cli_state *cli;
261         size_t sent;
262         const char *message;
263         uint16_t grp;
264 };
265
266 static void cli_message_started(struct tevent_req *subreq);
267 static void cli_message_sent(struct tevent_req *subreq);
268 static void cli_message_done(struct tevent_req *subreq);
269
270 struct tevent_req *cli_message_send(TALLOC_CTX *mem_ctx,
271                                     struct tevent_context *ev,
272                                     struct cli_state *cli,
273                                     const char *host, const char *username,
274                                     const char *message)
275 {
276         struct tevent_req *req, *subreq;
277         struct cli_message_state *state;
278
279         req = tevent_req_create(mem_ctx, &state, struct cli_message_state);
280         if (req == NULL) {
281                 return NULL;
282         }
283         state->ev = ev;
284         state->cli = cli;
285         state->sent = 0;
286         state->message = message;
287
288         subreq = cli_message_start_send(state, ev, cli, host, username);
289         if (tevent_req_nomem(subreq, req)) {
290                 return tevent_req_post(req, ev);
291         }
292         tevent_req_set_callback(subreq, cli_message_started, req);
293         return req;
294 }
295
296 static void cli_message_started(struct tevent_req *subreq)
297 {
298         struct tevent_req *req = tevent_req_callback_data(
299                 subreq, struct tevent_req);
300         struct cli_message_state *state = tevent_req_data(
301                 req, struct cli_message_state);
302         NTSTATUS status;
303         size_t thistime;
304
305         status = cli_message_start_recv(subreq, &state->grp);
306         TALLOC_FREE(subreq);
307         if (!NT_STATUS_IS_OK(status)) {
308                 tevent_req_nterror(req, status);
309                 return;
310         }
311
312         thistime = MIN(127, strlen(state->message));
313
314         subreq = cli_message_text_send(state, state->ev, state->cli,
315                                        state->grp, state->message, thistime);
316         if (tevent_req_nomem(subreq, req)) {
317                 return;
318         }
319         state->sent += thistime;
320         tevent_req_set_callback(subreq, cli_message_sent, req);
321 }
322
323 static void cli_message_sent(struct tevent_req *subreq)
324 {
325         struct tevent_req *req = tevent_req_callback_data(
326                 subreq, struct tevent_req);
327         struct cli_message_state *state = tevent_req_data(
328                 req, struct cli_message_state);
329         NTSTATUS status;
330         size_t left, thistime;
331
332         status = cli_message_text_recv(subreq);
333         TALLOC_FREE(subreq);
334         if (!NT_STATUS_IS_OK(status)) {
335                 tevent_req_nterror(req, status);
336                 return;
337         }
338
339         if (state->sent >= strlen(state->message)) {
340                 subreq = cli_message_end_send(state, state->ev, state->cli,
341                                               state->grp);
342                 if (tevent_req_nomem(subreq, req)) {
343                         return;
344                 }
345                 tevent_req_set_callback(subreq, cli_message_done, req);
346                 return;
347         }
348
349         left = strlen(state->message) - state->sent;
350         thistime = MIN(127, left);
351
352         subreq = cli_message_text_send(state, state->ev, state->cli,
353                                        state->grp,
354                                        state->message + state->sent,
355                                        thistime);
356         if (tevent_req_nomem(subreq, req)) {
357                 return;
358         }
359         state->sent += thistime;
360         tevent_req_set_callback(subreq, cli_message_sent, req);
361 }
362
363 static void cli_message_done(struct tevent_req *subreq)
364 {
365         struct tevent_req *req = tevent_req_callback_data(
366                 subreq, struct tevent_req);
367         NTSTATUS status;
368
369         status = cli_message_end_recv(subreq);
370         TALLOC_FREE(subreq);
371         if (!NT_STATUS_IS_OK(status)) {
372                 tevent_req_nterror(req, status);
373                 return;
374         }
375         tevent_req_done(req);
376 }
377
378 NTSTATUS cli_message_recv(struct tevent_req *req)
379 {
380         return tevent_req_simple_recv_ntstatus(req);
381 }
382
383 NTSTATUS cli_message(struct cli_state *cli, const char *host,
384                      const char *username, const char *message)
385 {
386         TALLOC_CTX *frame = talloc_stackframe();
387         struct tevent_context *ev;
388         struct tevent_req *req;
389         NTSTATUS status = NT_STATUS_OK;
390
391         if (smbXcli_conn_has_async_calls(cli->conn)) {
392                 /*
393                  * Can't use sync call while an async call is in flight
394                  */
395                 status = NT_STATUS_INVALID_PARAMETER;
396                 goto fail;
397         }
398
399         ev = samba_tevent_context_init(frame);
400         if (ev == NULL) {
401                 status = NT_STATUS_NO_MEMORY;
402                 goto fail;
403         }
404
405         req = cli_message_send(frame, ev, cli, host, username, message);
406         if (req == NULL) {
407                 status = NT_STATUS_NO_MEMORY;
408                 goto fail;
409         }
410
411         if (!tevent_req_poll(req, ev)) {
412                 status = map_nt_error_from_unix(errno);
413                 goto fail;
414         }
415
416         status = cli_message_recv(req);
417  fail:
418         TALLOC_FREE(frame);
419         return status;
420 }