s3: use nsec_time_diff instead of TspecDiff
[Samba.git] / source3 / libsmb / climessage.c
blob3777c41482200982bf70aab1c4224061364c6eba
1 /*
2 Unix SMB/CIFS implementation.
3 client message handling routines
4 Copyright (C) Andrew Tridgell 1994-1998
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.
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.
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/>.
20 #include "includes.h"
22 struct cli_message_start_state {
23 uint16_t grp;
26 static void cli_message_start_done(struct tevent_req *subreq);
28 static struct tevent_req *cli_message_start_send(TALLOC_CTX *mem_ctx,
29 struct tevent_context *ev,
30 struct cli_state *cli,
31 const char *host,
32 const char *username)
34 struct tevent_req *req, *subreq;
35 struct cli_message_start_state *state;
36 char *htmp = NULL;
37 char *utmp = NULL;
38 size_t hlen, ulen;
39 uint8_t *bytes, *p;
41 req = tevent_req_create(mem_ctx, &state,
42 struct cli_message_start_state);
43 if (req == NULL) {
44 return NULL;
47 if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
48 username, strlen(username)+1,
49 &utmp, &ulen, true)) {
50 goto fail;
52 if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
53 host, strlen(host)+1,
54 &htmp, &hlen, true)) {
55 goto fail;
58 bytes = talloc_array(state, uint8_t, ulen+hlen+2);
59 if (bytes == NULL) {
60 goto fail;
62 p = bytes;
64 *p++ = 4;
65 memcpy(p, utmp, ulen);
66 p += ulen;
67 *p++ = 4;
68 memcpy(p, htmp, hlen);
69 p += hlen;
70 TALLOC_FREE(htmp);
71 TALLOC_FREE(utmp);
73 subreq = cli_smb_send(state, ev, cli, SMBsendstrt, 0, 0, NULL,
74 talloc_get_size(bytes), bytes);
75 if (tevent_req_nomem(subreq, req)) {
76 return tevent_req_post(req, ev);
78 tevent_req_set_callback(subreq, cli_message_start_done, req);
79 return req;
80 fail:
81 TALLOC_FREE(htmp);
82 TALLOC_FREE(utmp);
83 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
84 return tevent_req_post(req, ev);
87 static void cli_message_start_done(struct tevent_req *subreq)
89 struct tevent_req *req = tevent_req_callback_data(
90 subreq, struct tevent_req);
91 struct cli_message_start_state *state = tevent_req_data(
92 req, struct cli_message_start_state);
93 NTSTATUS status;
94 uint8_t wct;
95 uint16_t *vwv;
96 uint8_t *inbuf;
98 status = cli_smb_recv(subreq, state, &inbuf, 0, &wct, &vwv,
99 NULL, NULL);
100 TALLOC_FREE(subreq);
101 if (!NT_STATUS_IS_OK(status)) {
102 TALLOC_FREE(subreq);
103 tevent_req_nterror(req, status);
104 return;
106 if (wct >= 1) {
107 state->grp = SVAL(vwv+0, 0);
108 } else {
109 state->grp = 0;
111 tevent_req_done(req);
114 static NTSTATUS cli_message_start_recv(struct tevent_req *req,
115 uint16_t *pgrp)
117 struct cli_message_start_state *state = tevent_req_data(
118 req, struct cli_message_start_state);
119 NTSTATUS status;
121 if (tevent_req_is_nterror(req, &status)) {
122 return status;
124 *pgrp = state->grp;
125 return NT_STATUS_OK;
128 struct cli_message_text_state {
129 uint16_t vwv;
132 static void cli_message_text_done(struct tevent_req *subreq);
134 static struct tevent_req *cli_message_text_send(TALLOC_CTX *mem_ctx,
135 struct tevent_context *ev,
136 struct cli_state *cli,
137 uint16_t grp,
138 const char *msg,
139 int msglen)
141 struct tevent_req *req, *subreq;
142 struct cli_message_text_state *state;
143 char *tmp;
144 size_t tmplen;
145 uint8_t *bytes;
147 req = tevent_req_create(mem_ctx, &state,
148 struct cli_message_text_state);
149 if (req == NULL) {
150 return NULL;
153 SSVAL(&state->vwv, 0, grp);
155 if (convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS, msg, msglen,
156 &tmp, &tmplen, true)) {
157 msg = tmp;
158 msglen = tmplen;
159 } else {
160 DEBUG(3, ("Conversion failed, sending message in UNIX "
161 "charset\n"));
162 tmp = NULL;
165 bytes = talloc_array(state, uint8_t, msglen+3);
166 if (tevent_req_nomem(bytes, req)) {
167 TALLOC_FREE(tmp);
168 return tevent_req_post(req, ev);
170 SCVAL(bytes, 0, 1); /* pad */
171 SSVAL(bytes+1, 0, msglen);
172 memcpy(bytes+3, msg, msglen);
173 TALLOC_FREE(tmp);
175 subreq = cli_smb_send(state, ev, cli, SMBsendtxt, 0, 1, &state->vwv,
176 talloc_get_size(bytes), bytes);
177 if (tevent_req_nomem(subreq, req)) {
178 return tevent_req_post(req, ev);
180 tevent_req_set_callback(subreq, cli_message_text_done, req);
181 return req;
184 static void cli_message_text_done(struct tevent_req *subreq)
186 struct tevent_req *req = tevent_req_callback_data(
187 subreq, struct tevent_req);
188 NTSTATUS status;
190 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
191 TALLOC_FREE(subreq);
192 if (!NT_STATUS_IS_OK(status)) {
193 tevent_req_nterror(req, status);
194 return;
196 tevent_req_done(req);
199 static NTSTATUS cli_message_text_recv(struct tevent_req *req)
201 return tevent_req_simple_recv_ntstatus(req);
204 struct cli_message_end_state {
205 uint16_t vwv;
208 static void cli_message_end_done(struct tevent_req *subreq);
210 static struct tevent_req *cli_message_end_send(TALLOC_CTX *mem_ctx,
211 struct tevent_context *ev,
212 struct cli_state *cli,
213 uint16_t grp)
215 struct tevent_req *req, *subreq;
216 struct cli_message_end_state *state;
218 req = tevent_req_create(mem_ctx, &state,
219 struct cli_message_end_state);
220 if (req == NULL) {
221 return NULL;
224 SSVAL(&state->vwv, 0, grp);
226 subreq = cli_smb_send(state, ev, cli, SMBsendend, 0, 1, &state->vwv,
227 0, NULL);
228 if (tevent_req_nomem(subreq, req)) {
229 return tevent_req_post(req, ev);
231 tevent_req_set_callback(subreq, cli_message_end_done, req);
232 return req;
235 static void cli_message_end_done(struct tevent_req *subreq)
237 struct tevent_req *req = tevent_req_callback_data(
238 subreq, struct tevent_req);
239 NTSTATUS status;
241 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
242 TALLOC_FREE(subreq);
243 if (!NT_STATUS_IS_OK(status)) {
244 tevent_req_nterror(req, status);
245 return;
247 tevent_req_done(req);
250 static NTSTATUS cli_message_end_recv(struct tevent_req *req)
252 return tevent_req_simple_recv_ntstatus(req);
255 struct cli_message_state {
256 struct tevent_context *ev;
257 struct cli_state *cli;
258 size_t sent;
259 const char *message;
260 uint16_t grp;
263 static void cli_message_started(struct tevent_req *subreq);
264 static void cli_message_sent(struct tevent_req *subreq);
265 static void cli_message_done(struct tevent_req *subreq);
267 struct tevent_req *cli_message_send(TALLOC_CTX *mem_ctx,
268 struct tevent_context *ev,
269 struct cli_state *cli,
270 const char *host, const char *username,
271 const char *message)
273 struct tevent_req *req, *subreq;
274 struct cli_message_state *state;
276 req = tevent_req_create(mem_ctx, &state, struct cli_message_state);
277 if (req == NULL) {
278 return NULL;
280 state->ev = ev;
281 state->cli = cli;
282 state->sent = 0;
283 state->message = message;
285 subreq = cli_message_start_send(state, ev, cli, host, username);
286 if (tevent_req_nomem(subreq, req)) {
287 return tevent_req_post(req, ev);
289 tevent_req_set_callback(subreq, cli_message_started, req);
290 return req;
293 static void cli_message_started(struct tevent_req *subreq)
295 struct tevent_req *req = tevent_req_callback_data(
296 subreq, struct tevent_req);
297 struct cli_message_state *state = tevent_req_data(
298 req, struct cli_message_state);
299 NTSTATUS status;
300 size_t thistime;
302 status = cli_message_start_recv(subreq, &state->grp);
303 TALLOC_FREE(subreq);
304 if (!NT_STATUS_IS_OK(status)) {
305 tevent_req_nterror(req, status);
306 return;
309 thistime = MIN(127, strlen(state->message));
311 subreq = cli_message_text_send(state, state->ev, state->cli,
312 state->grp, state->message, thistime);
313 if (tevent_req_nomem(subreq, req)) {
314 return;
316 state->sent += thistime;
317 tevent_req_set_callback(subreq, cli_message_sent, req);
320 static void cli_message_sent(struct tevent_req *subreq)
322 struct tevent_req *req = tevent_req_callback_data(
323 subreq, struct tevent_req);
324 struct cli_message_state *state = tevent_req_data(
325 req, struct cli_message_state);
326 NTSTATUS status;
327 size_t left, thistime;
329 status = cli_message_text_recv(subreq);
330 TALLOC_FREE(subreq);
331 if (!NT_STATUS_IS_OK(status)) {
332 tevent_req_nterror(req, status);
333 return;
336 if (state->sent >= strlen(state->message)) {
337 subreq = cli_message_end_send(state, state->ev, state->cli,
338 state->grp);
339 if (tevent_req_nomem(subreq, req)) {
340 return;
342 tevent_req_set_callback(subreq, cli_message_done, req);
343 return;
346 left = strlen(state->message) - state->sent;
347 thistime = MIN(127, left);
349 subreq = cli_message_text_send(state, state->ev, state->cli,
350 state->grp,
351 state->message + state->sent,
352 thistime);
353 if (tevent_req_nomem(subreq, req)) {
354 return;
356 state->sent += thistime;
357 tevent_req_set_callback(subreq, cli_message_sent, req);
360 static void cli_message_done(struct tevent_req *subreq)
362 struct tevent_req *req = tevent_req_callback_data(
363 subreq, struct tevent_req);
364 NTSTATUS status;
366 status = cli_message_end_recv(subreq);
367 TALLOC_FREE(subreq);
368 if (!NT_STATUS_IS_OK(status)) {
369 tevent_req_nterror(req, status);
370 return;
372 tevent_req_done(req);
375 NTSTATUS cli_message_recv(struct tevent_req *req)
377 return tevent_req_simple_recv_ntstatus(req);
380 NTSTATUS cli_message(struct cli_state *cli, const char *host,
381 const char *username, const char *message)
383 TALLOC_CTX *frame = talloc_stackframe();
384 struct event_context *ev;
385 struct tevent_req *req;
386 NTSTATUS status = NT_STATUS_OK;
388 if (cli_has_async_calls(cli)) {
390 * Can't use sync call while an async call is in flight
392 status = NT_STATUS_INVALID_PARAMETER;
393 goto fail;
396 ev = event_context_init(frame);
397 if (ev == NULL) {
398 status = NT_STATUS_NO_MEMORY;
399 goto fail;
402 req = cli_message_send(frame, ev, cli, host, username, message);
403 if (req == NULL) {
404 status = NT_STATUS_NO_MEMORY;
405 goto fail;
408 if (!tevent_req_poll(req, ev)) {
409 status = map_nt_error_from_unix(errno);
410 goto fail;
413 status = cli_message_recv(req);
414 fail:
415 TALLOC_FREE(frame);
416 return status;