Fix re-opened bug 8083 - "inherit owner = yes" doesn't interact correctly with vfs_ac...
[Samba.git] / source3 / libsmb / climessage.c
blob0993037a48e6a9bd09f0291fe679cef63130a532
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;
97 status = cli_smb_recv(subreq, 0, &wct, &vwv, NULL, NULL);
98 if (!NT_STATUS_IS_OK(status)) {
99 TALLOC_FREE(subreq);
100 tevent_req_nterror(req, status);
101 return;
103 if (wct >= 1) {
104 state->grp = SVAL(vwv+0, 0);
105 } else {
106 state->grp = 0;
108 TALLOC_FREE(subreq);
109 tevent_req_done(req);
112 static NTSTATUS cli_message_start_recv(struct tevent_req *req,
113 uint16_t *pgrp)
115 struct cli_message_start_state *state = tevent_req_data(
116 req, struct cli_message_start_state);
117 NTSTATUS status;
119 if (tevent_req_is_nterror(req, &status)) {
120 return status;
122 *pgrp = state->grp;
123 return NT_STATUS_OK;
126 struct cli_message_text_state {
127 uint16_t vwv;
130 static void cli_message_text_done(struct tevent_req *subreq);
132 static struct tevent_req *cli_message_text_send(TALLOC_CTX *mem_ctx,
133 struct tevent_context *ev,
134 struct cli_state *cli,
135 uint16_t grp,
136 const char *msg,
137 int msglen)
139 struct tevent_req *req, *subreq;
140 struct cli_message_text_state *state;
141 char *tmp;
142 size_t tmplen;
143 uint8_t *bytes;
145 req = tevent_req_create(mem_ctx, &state,
146 struct cli_message_text_state);
147 if (req == NULL) {
148 return NULL;
151 SSVAL(&state->vwv, 0, grp);
153 if (convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS, msg, msglen,
154 &tmp, &tmplen, true)) {
155 msg = tmp;
156 msglen = tmplen;
157 } else {
158 DEBUG(3, ("Conversion failed, sending message in UNIX "
159 "charset\n"));
160 tmp = NULL;
163 bytes = talloc_array(state, uint8_t, msglen+3);
164 if (tevent_req_nomem(bytes, req)) {
165 TALLOC_FREE(tmp);
166 return tevent_req_post(req, ev);
168 SCVAL(bytes, 0, 1); /* pad */
169 SSVAL(bytes+1, 0, msglen);
170 memcpy(bytes+3, msg, msglen);
171 TALLOC_FREE(tmp);
173 subreq = cli_smb_send(state, ev, cli, SMBsendtxt, 0, 1, &state->vwv,
174 talloc_get_size(bytes), bytes);
175 if (tevent_req_nomem(subreq, req)) {
176 return tevent_req_post(req, ev);
178 tevent_req_set_callback(subreq, cli_message_text_done, req);
179 return req;
182 static void cli_message_text_done(struct tevent_req *subreq)
184 struct tevent_req *req = tevent_req_callback_data(
185 subreq, struct tevent_req);
186 NTSTATUS status;
188 status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
189 TALLOC_FREE(subreq);
190 if (!NT_STATUS_IS_OK(status)) {
191 tevent_req_nterror(req, status);
192 return;
194 tevent_req_done(req);
197 static NTSTATUS cli_message_text_recv(struct tevent_req *req)
199 return tevent_req_simple_recv_ntstatus(req);
202 struct cli_message_end_state {
203 uint16_t vwv;
206 static void cli_message_end_done(struct tevent_req *subreq);
208 static struct tevent_req *cli_message_end_send(TALLOC_CTX *mem_ctx,
209 struct tevent_context *ev,
210 struct cli_state *cli,
211 uint16_t grp)
213 struct tevent_req *req, *subreq;
214 struct cli_message_end_state *state;
216 req = tevent_req_create(mem_ctx, &state,
217 struct cli_message_end_state);
218 if (req == NULL) {
219 return NULL;
222 SSVAL(&state->vwv, 0, grp);
224 subreq = cli_smb_send(state, ev, cli, SMBsendend, 0, 1, &state->vwv,
225 0, NULL);
226 if (tevent_req_nomem(subreq, req)) {
227 return tevent_req_post(req, ev);
229 tevent_req_set_callback(subreq, cli_message_end_done, req);
230 return req;
233 static void cli_message_end_done(struct tevent_req *subreq)
235 struct tevent_req *req = tevent_req_callback_data(
236 subreq, struct tevent_req);
237 NTSTATUS status;
239 status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
240 TALLOC_FREE(subreq);
241 if (!NT_STATUS_IS_OK(status)) {
242 tevent_req_nterror(req, status);
243 return;
245 tevent_req_done(req);
248 static NTSTATUS cli_message_end_recv(struct tevent_req *req)
250 return tevent_req_simple_recv_ntstatus(req);
253 struct cli_message_state {
254 struct tevent_context *ev;
255 struct cli_state *cli;
256 size_t sent;
257 const char *message;
258 uint16_t grp;
261 static void cli_message_started(struct tevent_req *subreq);
262 static void cli_message_sent(struct tevent_req *subreq);
263 static void cli_message_done(struct tevent_req *subreq);
265 struct tevent_req *cli_message_send(TALLOC_CTX *mem_ctx,
266 struct tevent_context *ev,
267 struct cli_state *cli,
268 const char *host, const char *username,
269 const char *message)
271 struct tevent_req *req, *subreq;
272 struct cli_message_state *state;
274 req = tevent_req_create(mem_ctx, &state, struct cli_message_state);
275 if (req == NULL) {
276 return NULL;
278 state->ev = ev;
279 state->cli = cli;
280 state->sent = 0;
281 state->message = message;
283 subreq = cli_message_start_send(state, ev, cli, host, username);
284 if (tevent_req_nomem(subreq, req)) {
285 return tevent_req_post(req, ev);
287 tevent_req_set_callback(subreq, cli_message_started, req);
288 return req;
291 static void cli_message_started(struct tevent_req *subreq)
293 struct tevent_req *req = tevent_req_callback_data(
294 subreq, struct tevent_req);
295 struct cli_message_state *state = tevent_req_data(
296 req, struct cli_message_state);
297 NTSTATUS status;
298 size_t thistime;
300 status = cli_message_start_recv(subreq, &state->grp);
301 TALLOC_FREE(subreq);
302 if (!NT_STATUS_IS_OK(status)) {
303 tevent_req_nterror(req, status);
304 return;
307 thistime = MIN(127, strlen(state->message));
309 subreq = cli_message_text_send(state, state->ev, state->cli,
310 state->grp, state->message, thistime);
311 if (tevent_req_nomem(subreq, req)) {
312 return;
314 state->sent += thistime;
315 tevent_req_set_callback(subreq, cli_message_sent, req);
318 static void cli_message_sent(struct tevent_req *subreq)
320 struct tevent_req *req = tevent_req_callback_data(
321 subreq, struct tevent_req);
322 struct cli_message_state *state = tevent_req_data(
323 req, struct cli_message_state);
324 NTSTATUS status;
325 size_t left, thistime;
327 status = cli_message_text_recv(subreq);
328 TALLOC_FREE(subreq);
329 if (!NT_STATUS_IS_OK(status)) {
330 tevent_req_nterror(req, status);
331 return;
334 if (state->sent >= strlen(state->message)) {
335 subreq = cli_message_end_send(state, state->ev, state->cli,
336 state->grp);
337 if (tevent_req_nomem(subreq, req)) {
338 return;
340 tevent_req_set_callback(subreq, cli_message_done, req);
341 return;
344 left = strlen(state->message) - state->sent;
345 thistime = MIN(127, left);
347 subreq = cli_message_text_send(state, state->ev, state->cli,
348 state->grp,
349 state->message + state->sent,
350 thistime);
351 if (tevent_req_nomem(subreq, req)) {
352 return;
354 state->sent += thistime;
355 tevent_req_set_callback(subreq, cli_message_sent, req);
358 static void cli_message_done(struct tevent_req *subreq)
360 struct tevent_req *req = tevent_req_callback_data(
361 subreq, struct tevent_req);
362 NTSTATUS status;
364 status = cli_message_end_recv(subreq);
365 TALLOC_FREE(subreq);
366 if (!NT_STATUS_IS_OK(status)) {
367 tevent_req_nterror(req, status);
368 return;
370 tevent_req_done(req);
373 NTSTATUS cli_message_recv(struct tevent_req *req)
375 return tevent_req_simple_recv_ntstatus(req);
378 NTSTATUS cli_message(struct cli_state *cli, const char *host,
379 const char *username, const char *message)
381 TALLOC_CTX *frame = talloc_stackframe();
382 struct event_context *ev;
383 struct tevent_req *req;
384 NTSTATUS status = NT_STATUS_OK;
386 if (cli_has_async_calls(cli)) {
388 * Can't use sync call while an async call is in flight
390 status = NT_STATUS_INVALID_PARAMETER;
391 goto fail;
394 ev = event_context_init(frame);
395 if (ev == NULL) {
396 status = NT_STATUS_NO_MEMORY;
397 goto fail;
400 req = cli_message_send(frame, ev, cli, host, username, message);
401 if (req == NULL) {
402 status = NT_STATUS_NO_MEMORY;
403 goto fail;
406 if (!tevent_req_poll(req, ev)) {
407 status = map_nt_error_from_unix(errno);
408 goto fail;
411 status = cli_message_recv(req);
412 fail:
413 TALLOC_FREE(frame);
414 return status;