• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source3/libsmb/
1/*
2   Unix SMB/CIFS implementation.
3   Infrastructure for async SMB client requests
4   Copyright (C) Volker Lendecke 2008
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
22/*
23 * Read an smb packet asynchronously, discard keepalives
24 */
25
26struct read_smb_state {
27	struct tevent_context *ev;
28	int fd;
29	uint8_t *buf;
30};
31
32static ssize_t read_smb_more(uint8_t *buf, size_t buflen, void *private_data);
33static void read_smb_done(struct tevent_req *subreq);
34
35static struct tevent_req *read_smb_send(TALLOC_CTX *mem_ctx,
36					struct tevent_context *ev,
37					int fd)
38{
39	struct tevent_req *result, *subreq;
40	struct read_smb_state *state;
41
42	result = tevent_req_create(mem_ctx, &state, struct read_smb_state);
43	if (result == NULL) {
44		return NULL;
45	}
46	state->ev = ev;
47	state->fd = fd;
48
49	subreq = read_packet_send(state, ev, fd, 4, read_smb_more, NULL);
50	if (subreq == NULL) {
51		goto fail;
52	}
53	tevent_req_set_callback(subreq, read_smb_done, result);
54	return result;
55 fail:
56	TALLOC_FREE(result);
57	return NULL;
58}
59
60static ssize_t read_smb_more(uint8_t *buf, size_t buflen, void *private_data)
61{
62	if (buflen > 4) {
63		return 0;	/* We've been here, we're done */
64	}
65	return smb_len_large(buf);
66}
67
68static void read_smb_done(struct tevent_req *subreq)
69{
70	struct tevent_req *req = tevent_req_callback_data(
71		subreq, struct tevent_req);
72	struct read_smb_state *state = tevent_req_data(
73		req, struct read_smb_state);
74	ssize_t len;
75	int err;
76
77	len = read_packet_recv(subreq, state, &state->buf, &err);
78	TALLOC_FREE(subreq);
79	if (len == -1) {
80		tevent_req_error(req, err);
81		return;
82	}
83
84	if (CVAL(state->buf, 0) == SMBkeepalive) {
85		subreq = read_packet_send(state, state->ev, state->fd, 4,
86					  read_smb_more, NULL);
87		if (tevent_req_nomem(subreq, req)) {
88			return;
89		}
90		tevent_req_set_callback(subreq, read_smb_done, req);
91		return;
92	}
93	tevent_req_done(req);
94}
95
96static ssize_t read_smb_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
97			     uint8_t **pbuf, int *perrno)
98{
99	struct read_smb_state *state = tevent_req_data(
100		req, struct read_smb_state);
101
102	if (tevent_req_is_unix_error(req, perrno)) {
103		return -1;
104	}
105	*pbuf = talloc_move(mem_ctx, &state->buf);
106	return talloc_get_size(*pbuf);
107}
108
109/**
110 * Fetch an error out of a NBT packet
111 * @param[in] buf	The SMB packet
112 * @retval		The error, converted to NTSTATUS
113 */
114
115NTSTATUS cli_pull_error(char *buf)
116{
117	uint32_t flags2 = SVAL(buf, smb_flg2);
118
119	if (flags2 & FLAGS2_32_BIT_ERROR_CODES) {
120		return NT_STATUS(IVAL(buf, smb_rcls));
121	}
122
123	/* if the client uses dos errors, but there is no error,
124	   we should return no error here, otherwise it looks
125	   like an unknown bad NT_STATUS. jmcd */
126	if (CVAL(buf, smb_rcls) == 0)
127		return NT_STATUS_OK;
128
129	return NT_STATUS_DOS(CVAL(buf, smb_rcls), SVAL(buf,smb_err));
130}
131
132/**
133 * Compatibility helper for the sync APIs: Fake NTSTATUS in cli->inbuf
134 * @param[in] cli	The client connection that just received an error
135 * @param[in] status	The error to set on "cli"
136 */
137
138void cli_set_error(struct cli_state *cli, NTSTATUS status)
139{
140	uint32_t flags2 = SVAL(cli->inbuf, smb_flg2);
141
142	if (NT_STATUS_IS_DOS(status)) {
143		SSVAL(cli->inbuf, smb_flg2,
144		      flags2 & ~FLAGS2_32_BIT_ERROR_CODES);
145		SCVAL(cli->inbuf, smb_rcls, NT_STATUS_DOS_CLASS(status));
146		SSVAL(cli->inbuf, smb_err, NT_STATUS_DOS_CODE(status));
147		return;
148	}
149
150	SSVAL(cli->inbuf, smb_flg2, flags2 | FLAGS2_32_BIT_ERROR_CODES);
151	SIVAL(cli->inbuf, smb_rcls, NT_STATUS_V(status));
152	return;
153}
154
155/**
156 * Figure out if there is an andx command behind the current one
157 * @param[in] buf	The smb buffer to look at
158 * @param[in] ofs	The offset to the wct field that is followed by the cmd
159 * @retval Is there a command following?
160 */
161
162static bool have_andx_command(const char *buf, uint16_t ofs)
163{
164	uint8_t wct;
165	size_t buflen = talloc_get_size(buf);
166
167	if ((ofs == buflen-1) || (ofs == buflen)) {
168		return false;
169	}
170
171	wct = CVAL(buf, ofs);
172	if (wct < 2) {
173		/*
174		 * Not enough space for the command and a following pointer
175		 */
176		return false;
177	}
178	return (CVAL(buf, ofs+1) != 0xff);
179}
180
181#define MAX_SMB_IOV 5
182
183struct cli_smb_state {
184	struct tevent_context *ev;
185	struct cli_state *cli;
186	uint8_t header[smb_wct+1]; /* Space for the header including the wct */
187
188	/*
189	 * For normal requests, cli_smb_req_send chooses a mid. Secondary
190	 * trans requests need to use the mid of the primary request, so we
191	 * need a place to store it. Assume it's set if != 0.
192	 */
193	uint16_t mid;
194
195	uint16_t *vwv;
196	uint8_t bytecount_buf[2];
197
198	struct iovec iov[MAX_SMB_IOV+3];
199	int iov_count;
200
201	uint8_t *inbuf;
202	uint32_t seqnum;
203	int chain_num;
204	struct tevent_req **chained_requests;
205};
206
207static uint16_t cli_alloc_mid(struct cli_state *cli)
208{
209	int num_pending = talloc_array_length(cli->pending);
210	uint16_t result;
211
212	while (true) {
213		int i;
214
215		result = cli->mid++;
216		if ((result == 0) || (result == 0xffff)) {
217			continue;
218		}
219
220		for (i=0; i<num_pending; i++) {
221			if (result == cli_smb_req_mid(cli->pending[i])) {
222				break;
223			}
224		}
225
226		if (i == num_pending) {
227			return result;
228		}
229	}
230}
231
232void cli_smb_req_unset_pending(struct tevent_req *req)
233{
234	struct cli_smb_state *state = tevent_req_data(
235		req, struct cli_smb_state);
236	struct cli_state *cli = state->cli;
237	int num_pending = talloc_array_length(cli->pending);
238	int i;
239
240	if (num_pending == 1) {
241		/*
242		 * The pending read_smb tevent_req is a child of
243		 * cli->pending. So if nothing is pending anymore, we need to
244		 * delete the socket read fde.
245		 */
246		TALLOC_FREE(cli->pending);
247		return;
248	}
249
250	for (i=0; i<num_pending; i++) {
251		if (req == cli->pending[i]) {
252			break;
253		}
254	}
255	if (i == num_pending) {
256		/*
257		 * Something's seriously broken. Just returning here is the
258		 * right thing nevertheless, the point of this routine is to
259		 * remove ourselves from cli->pending.
260		 */
261		return;
262	}
263
264	/*
265	 * Remove ourselves from the cli->pending array
266	 */
267	if (num_pending > 1) {
268		cli->pending[i] = cli->pending[num_pending-1];
269	}
270
271	/*
272	 * No NULL check here, we're shrinking by sizeof(void *), and
273	 * talloc_realloc just adjusts the size for this.
274	 */
275	cli->pending = talloc_realloc(NULL, cli->pending, struct tevent_req *,
276				      num_pending - 1);
277	return;
278}
279
280static int cli_smb_req_destructor(struct tevent_req *req)
281{
282	cli_smb_req_unset_pending(req);
283	return 0;
284}
285
286static void cli_smb_received(struct tevent_req *subreq);
287
288bool cli_smb_req_set_pending(struct tevent_req *req)
289{
290	struct cli_smb_state *state = tevent_req_data(
291		req, struct cli_smb_state);
292	struct cli_state *cli;
293	struct tevent_req **pending;
294	int num_pending;
295	struct tevent_req *subreq;
296
297	cli = state->cli;
298	num_pending = talloc_array_length(cli->pending);
299
300	pending = talloc_realloc(cli, cli->pending, struct tevent_req *,
301				 num_pending+1);
302	if (pending == NULL) {
303		return false;
304	}
305	pending[num_pending] = req;
306	cli->pending = pending;
307	talloc_set_destructor(req, cli_smb_req_destructor);
308
309	if (num_pending > 0) {
310		return true;
311	}
312
313	/*
314	 * We're the first ones, add the read_smb request that waits for the
315	 * answer from the server
316	 */
317	subreq = read_smb_send(cli->pending, state->ev, cli->fd);
318	if (subreq == NULL) {
319		cli_smb_req_unset_pending(req);
320		return false;
321	}
322	tevent_req_set_callback(subreq, cli_smb_received, cli);
323	return true;
324}
325
326/*
327 * Fetch a smb request's mid. Only valid after the request has been sent by
328 * cli_smb_req_send().
329 */
330uint16_t cli_smb_req_mid(struct tevent_req *req)
331{
332	struct cli_smb_state *state = tevent_req_data(
333		req, struct cli_smb_state);
334	return SVAL(state->header, smb_mid);
335}
336
337void cli_smb_req_set_mid(struct tevent_req *req, uint16_t mid)
338{
339	struct cli_smb_state *state = tevent_req_data(
340		req, struct cli_smb_state);
341	state->mid = mid;
342}
343
344static size_t iov_len(const struct iovec *iov, int count)
345{
346	size_t result = 0;
347	int i;
348	for (i=0; i<count; i++) {
349		result += iov[i].iov_len;
350	}
351	return result;
352}
353
354static uint8_t *iov_concat(TALLOC_CTX *mem_ctx, const struct iovec *iov,
355			   int count)
356{
357	size_t len = iov_len(iov, count);
358	size_t copied;
359	uint8_t *buf;
360	int i;
361
362	buf = talloc_array(mem_ctx, uint8_t, len);
363	if (buf == NULL) {
364		return NULL;
365	}
366	copied = 0;
367	for (i=0; i<count; i++) {
368		memcpy(buf+copied, iov[i].iov_base, iov[i].iov_len);
369		copied += iov[i].iov_len;
370	}
371	return buf;
372}
373
374struct tevent_req *cli_smb_req_create(TALLOC_CTX *mem_ctx,
375				      struct event_context *ev,
376				      struct cli_state *cli,
377				      uint8_t smb_command,
378				      uint8_t additional_flags,
379				      uint8_t wct, uint16_t *vwv,
380				      int iov_count,
381				      struct iovec *bytes_iov)
382{
383	struct tevent_req *result;
384	struct cli_smb_state *state;
385	struct timeval endtime;
386
387	if (iov_count > MAX_SMB_IOV) {
388		/*
389		 * Should not happen :-)
390		 */
391		return NULL;
392	}
393
394	result = tevent_req_create(mem_ctx, &state, struct cli_smb_state);
395	if (result == NULL) {
396		return NULL;
397	}
398	state->ev = ev;
399	state->cli = cli;
400	state->mid = 0;		/* Set to auto-choose in cli_smb_req_send */
401	state->chain_num = 0;
402	state->chained_requests = NULL;
403
404	cli_setup_packet_buf(cli, (char *)state->header);
405	SCVAL(state->header, smb_com, smb_command);
406	SSVAL(state->header, smb_tid, cli->cnum);
407	SCVAL(state->header, smb_wct, wct);
408
409	state->vwv = vwv;
410
411	SSVAL(state->bytecount_buf, 0, iov_len(bytes_iov, iov_count));
412
413	state->iov[0].iov_base = (void *)state->header;
414	state->iov[0].iov_len  = sizeof(state->header);
415	state->iov[1].iov_base = (void *)state->vwv;
416	state->iov[1].iov_len  = wct * sizeof(uint16_t);
417	state->iov[2].iov_base = (void *)state->bytecount_buf;
418	state->iov[2].iov_len  = sizeof(uint16_t);
419
420	if (iov_count != 0) {
421		memcpy(&state->iov[3], bytes_iov,
422		       iov_count * sizeof(*bytes_iov));
423	}
424	state->iov_count = iov_count + 3;
425
426	endtime = timeval_current_ofs(0, cli->timeout * 1000);
427	if (!tevent_req_set_endtime(result, ev, endtime)) {
428		tevent_req_nomem(NULL, result);
429	}
430	return result;
431}
432
433static NTSTATUS cli_signv(struct cli_state *cli, struct iovec *iov, int count,
434		          uint32_t *seqnum)
435{
436	uint8_t *buf;
437
438	/*
439	 * Obvious optimization: Make cli_calculate_sign_mac work with struct
440	 * iovec directly. MD5Update would do that just fine.
441	 */
442
443	if ((count <= 0) || (iov[0].iov_len < smb_wct)) {
444		return NT_STATUS_INVALID_PARAMETER;
445	}
446
447	buf = iov_concat(talloc_tos(), iov, count);
448	if (buf == NULL) {
449		return NT_STATUS_NO_MEMORY;
450	}
451
452	cli_calculate_sign_mac(cli, (char *)buf, seqnum);
453	memcpy(iov[0].iov_base, buf, iov[0].iov_len);
454
455	TALLOC_FREE(buf);
456	return NT_STATUS_OK;
457}
458
459static void cli_smb_sent(struct tevent_req *subreq);
460
461static NTSTATUS cli_smb_req_iov_send(struct tevent_req *req,
462				     struct cli_smb_state *state,
463				     struct iovec *iov, int iov_count)
464{
465	struct tevent_req *subreq;
466	NTSTATUS status;
467
468	if (state->cli->fd == -1) {
469		return NT_STATUS_CONNECTION_INVALID;
470	}
471
472	if (iov[0].iov_len < smb_wct) {
473		return NT_STATUS_INVALID_PARAMETER;
474	}
475
476	if (state->mid != 0) {
477		SSVAL(iov[0].iov_base, smb_mid, state->mid);
478	} else {
479		uint16_t mid = cli_alloc_mid(state->cli);
480		SSVAL(iov[0].iov_base, smb_mid, mid);
481	}
482
483	smb_setlen((char *)iov[0].iov_base, iov_len(iov, iov_count) - 4);
484
485	status = cli_signv(state->cli, iov, iov_count, &state->seqnum);
486
487	if (!NT_STATUS_IS_OK(status)) {
488		return status;
489	}
490
491	if (cli_encryption_on(state->cli)) {
492		char *buf, *enc_buf;
493
494		buf = (char *)iov_concat(talloc_tos(), iov, iov_count);
495		if (buf == NULL) {
496			return NT_STATUS_NO_MEMORY;
497		}
498		status = cli_encrypt_message(state->cli, (char *)buf,
499					     &enc_buf);
500		TALLOC_FREE(buf);
501		if (!NT_STATUS_IS_OK(status)) {
502			DEBUG(0, ("Error in encrypting client message: %s\n",
503				  nt_errstr(status)));
504			return status;
505		}
506		buf = (char *)talloc_memdup(state, enc_buf,
507					    smb_len(enc_buf)+4);
508		SAFE_FREE(enc_buf);
509		if (buf == NULL) {
510			return NT_STATUS_NO_MEMORY;
511		}
512		iov[0].iov_base = (void *)buf;
513		iov[0].iov_len = talloc_get_size(buf);
514		iov_count = 1;
515	}
516	subreq = writev_send(state, state->ev, state->cli->outgoing,
517			     state->cli->fd, false, iov, iov_count);
518	if (subreq == NULL) {
519		return NT_STATUS_NO_MEMORY;
520	}
521	tevent_req_set_callback(subreq, cli_smb_sent, req);
522	return NT_STATUS_OK;
523}
524
525NTSTATUS cli_smb_req_send(struct tevent_req *req)
526{
527	struct cli_smb_state *state = tevent_req_data(
528		req, struct cli_smb_state);
529
530	return cli_smb_req_iov_send(req, state, state->iov, state->iov_count);
531}
532
533struct tevent_req *cli_smb_send(TALLOC_CTX *mem_ctx,
534				struct event_context *ev,
535				struct cli_state *cli,
536				uint8_t smb_command,
537				uint8_t additional_flags,
538				uint8_t wct, uint16_t *vwv,
539				uint32_t num_bytes,
540				const uint8_t *bytes)
541{
542	struct tevent_req *req;
543	struct iovec iov;
544	NTSTATUS status;
545
546	iov.iov_base = CONST_DISCARD(void *, bytes);
547	iov.iov_len = num_bytes;
548
549	req = cli_smb_req_create(mem_ctx, ev, cli, smb_command,
550				 additional_flags, wct, vwv, 1, &iov);
551	if (req == NULL) {
552		return NULL;
553	}
554
555	status = cli_smb_req_send(req);
556	if (!NT_STATUS_IS_OK(status)) {
557		tevent_req_nterror(req, status);
558		return tevent_req_post(req, ev);
559	}
560	return req;
561}
562
563static void cli_smb_sent(struct tevent_req *subreq)
564{
565	struct tevent_req *req = tevent_req_callback_data(
566		subreq, struct tevent_req);
567	struct cli_smb_state *state = tevent_req_data(
568		req, struct cli_smb_state);
569	ssize_t nwritten;
570	int err;
571
572	nwritten = writev_recv(subreq, &err);
573	TALLOC_FREE(subreq);
574	if (nwritten == -1) {
575		if (state->cli->fd != -1) {
576			close(state->cli->fd);
577			state->cli->fd = -1;
578		}
579		tevent_req_nterror(req, map_nt_error_from_unix(err));
580		return;
581	}
582
583	switch (CVAL(state->header, smb_com)) {
584	case SMBtranss:
585	case SMBtranss2:
586	case SMBnttranss:
587	case SMBntcancel:
588		state->inbuf = NULL;
589		tevent_req_done(req);
590		return;
591	case SMBlockingX:
592		if ((CVAL(state->header, smb_wct) == 8) &&
593		    (CVAL(state->vwv+3, 0) == LOCKING_ANDX_OPLOCK_RELEASE)) {
594			state->inbuf = NULL;
595			tevent_req_done(req);
596			return;
597		}
598	}
599
600	if (!cli_smb_req_set_pending(req)) {
601		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
602		return;
603	}
604}
605
606static void cli_smb_received(struct tevent_req *subreq)
607{
608	struct cli_state *cli = tevent_req_callback_data(
609		subreq, struct cli_state);
610	struct tevent_req *req;
611	struct cli_smb_state *state;
612	struct tevent_context *ev;
613	NTSTATUS status;
614	uint8_t *inbuf;
615	ssize_t received;
616	int num_pending;
617	int i, err;
618	uint16_t mid;
619	bool oplock_break;
620
621	received = read_smb_recv(subreq, talloc_tos(), &inbuf, &err);
622	TALLOC_FREE(subreq);
623	if (received == -1) {
624		if (cli->fd != -1) {
625			close(cli->fd);
626			cli->fd = -1;
627		}
628		status = map_nt_error_from_unix(err);
629		goto fail;
630	}
631
632	if ((IVAL(inbuf, 4) != 0x424d53ff) /* 0xFF"SMB" */
633	    && (SVAL(inbuf, 4) != 0x45ff)) /* 0xFF"E" */ {
634		DEBUG(10, ("Got non-SMB PDU\n"));
635		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
636		goto fail;
637	}
638
639	if (cli_encryption_on(cli) && (CVAL(inbuf, 0) == 0)) {
640		uint16_t enc_ctx_num;
641
642		status = get_enc_ctx_num(inbuf, &enc_ctx_num);
643		if (!NT_STATUS_IS_OK(status)) {
644			DEBUG(10, ("get_enc_ctx_num returned %s\n",
645				   nt_errstr(status)));
646			goto fail;
647		}
648
649		if (enc_ctx_num != cli->trans_enc_state->enc_ctx_num) {
650			DEBUG(10, ("wrong enc_ctx %d, expected %d\n",
651				   enc_ctx_num,
652				   cli->trans_enc_state->enc_ctx_num));
653			status = NT_STATUS_INVALID_HANDLE;
654			goto fail;
655		}
656
657		status = common_decrypt_buffer(cli->trans_enc_state,
658					       (char *)inbuf);
659		if (!NT_STATUS_IS_OK(status)) {
660			DEBUG(10, ("common_decrypt_buffer returned %s\n",
661				   nt_errstr(status)));
662			goto fail;
663		}
664	}
665
666	mid = SVAL(inbuf, smb_mid);
667	num_pending = talloc_array_length(cli->pending);
668
669	for (i=0; i<num_pending; i++) {
670		if (mid == cli_smb_req_mid(cli->pending[i])) {
671			break;
672		}
673	}
674	if (i == num_pending) {
675		/* Dump unexpected reply */
676		TALLOC_FREE(inbuf);
677		goto done;
678	}
679
680	oplock_break = false;
681
682	if (mid == 0xffff) {
683		/*
684		 * Paranoia checks that this is really an oplock break request.
685		 */
686		oplock_break = (smb_len(inbuf) == 51); /* hdr + 8 words */
687		oplock_break &= ((CVAL(inbuf, smb_flg) & FLAG_REPLY) == 0);
688		oplock_break &= (CVAL(inbuf, smb_com) == SMBlockingX);
689		oplock_break &= (SVAL(inbuf, smb_vwv6) == 0);
690		oplock_break &= (SVAL(inbuf, smb_vwv7) == 0);
691
692		if (!oplock_break) {
693			/* Dump unexpected reply */
694			TALLOC_FREE(inbuf);
695			goto done;
696		}
697	}
698
699	req = cli->pending[i];
700	state = tevent_req_data(req, struct cli_smb_state);
701	ev = state->ev;
702
703	if (!oplock_break /* oplock breaks are not signed */
704	    && !cli_check_sign_mac(cli, (char *)inbuf, state->seqnum+1)) {
705		DEBUG(10, ("cli_check_sign_mac failed\n"));
706		TALLOC_FREE(inbuf);
707		status = NT_STATUS_ACCESS_DENIED;
708		close(cli->fd);
709		cli->fd = -1;
710		goto fail;
711	}
712
713	if (state->chained_requests == NULL) {
714		state->inbuf = talloc_move(state, &inbuf);
715		talloc_set_destructor(req, NULL);
716		cli_smb_req_destructor(req);
717		tevent_req_done(req);
718	} else {
719		struct tevent_req **chain = talloc_move(
720			talloc_tos(), &state->chained_requests);
721		int num_chained = talloc_array_length(chain);
722
723		for (i=0; i<num_chained; i++) {
724			state = tevent_req_data(chain[i], struct
725						cli_smb_state);
726			state->inbuf = inbuf;
727			state->chain_num = i;
728			tevent_req_done(chain[i]);
729		}
730		TALLOC_FREE(inbuf);
731		TALLOC_FREE(chain);
732	}
733 done:
734	if (talloc_array_length(cli->pending) > 0) {
735		/*
736		 * Set up another read request for the other pending cli_smb
737		 * requests
738		 */
739		state = tevent_req_data(cli->pending[0], struct cli_smb_state);
740		subreq = read_smb_send(cli->pending, state->ev, cli->fd);
741		if (subreq == NULL) {
742			status = NT_STATUS_NO_MEMORY;
743			goto fail;
744		}
745		tevent_req_set_callback(subreq, cli_smb_received, cli);
746	}
747	return;
748 fail:
749	/*
750	 * Cancel all pending requests. We don't do a for-loop walking
751	 * cli->pending because that array changes in
752	 * cli_smb_req_destructor().
753	 */
754	while (talloc_array_length(cli->pending) > 0) {
755		req = cli->pending[0];
756		talloc_set_destructor(req, NULL);
757		cli_smb_req_destructor(req);
758		tevent_req_nterror(req, status);
759	}
760}
761
762NTSTATUS cli_smb_recv(struct tevent_req *req, uint8_t min_wct,
763		      uint8_t *pwct, uint16_t **pvwv,
764		      uint32_t *pnum_bytes, uint8_t **pbytes)
765{
766	struct cli_smb_state *state = tevent_req_data(
767		req, struct cli_smb_state);
768	NTSTATUS status = NT_STATUS_OK;
769	uint8_t cmd, wct;
770	uint16_t num_bytes;
771	size_t wct_ofs, bytes_offset;
772	int i;
773
774	if (tevent_req_is_nterror(req, &status)) {
775		return status;
776	}
777
778	if (state->inbuf == NULL) {
779		/* This was a request without a reply */
780		return NT_STATUS_OK;
781	}
782
783	wct_ofs = smb_wct;
784	cmd = CVAL(state->inbuf, smb_com);
785
786	for (i=0; i<state->chain_num; i++) {
787		if (i < state->chain_num-1) {
788			if (cmd == 0xff) {
789				return NT_STATUS_REQUEST_ABORTED;
790			}
791			if (!is_andx_req(cmd)) {
792				return NT_STATUS_INVALID_NETWORK_RESPONSE;
793			}
794		}
795
796		if (!have_andx_command((char *)state->inbuf, wct_ofs)) {
797			/*
798			 * This request was not completed because a previous
799			 * request in the chain had received an error.
800			 */
801			return NT_STATUS_REQUEST_ABORTED;
802		}
803
804		wct_ofs = SVAL(state->inbuf, wct_ofs + 3);
805
806		/*
807		 * Skip the all-present length field. No overflow, we've just
808		 * put a 16-bit value into a size_t.
809		 */
810		wct_ofs += 4;
811
812		if (wct_ofs+2 > talloc_get_size(state->inbuf)) {
813			return NT_STATUS_INVALID_NETWORK_RESPONSE;
814		}
815
816		cmd = CVAL(state->inbuf, wct_ofs + 1);
817	}
818
819	status = cli_pull_error((char *)state->inbuf);
820
821	if (!have_andx_command((char *)state->inbuf, wct_ofs)
822	    && NT_STATUS_IS_ERR(status)) {
823		/*
824		 * The last command takes the error code. All further commands
825		 * down the requested chain will get a
826		 * NT_STATUS_REQUEST_ABORTED.
827		 */
828		return status;
829	}
830
831no_err:
832
833	wct = CVAL(state->inbuf, wct_ofs);
834	bytes_offset = wct_ofs + 1 + wct * sizeof(uint16_t);
835	num_bytes = SVAL(state->inbuf, bytes_offset);
836
837	if (wct < min_wct) {
838		return NT_STATUS_INVALID_NETWORK_RESPONSE;
839	}
840
841	/*
842	 * wct_ofs is a 16-bit value plus 4, wct is a 8-bit value, num_bytes
843	 * is a 16-bit value. So bytes_offset being size_t should be far from
844	 * wrapping.
845	 */
846	if ((bytes_offset + 2 > talloc_get_size(state->inbuf))
847	    || (bytes_offset > 0xffff)) {
848		return NT_STATUS_INVALID_NETWORK_RESPONSE;
849	}
850
851	if (pwct != NULL) {
852		*pwct = wct;
853	}
854	if (pvwv != NULL) {
855		*pvwv = (uint16_t *)(state->inbuf + wct_ofs + 1);
856	}
857	if (pnum_bytes != NULL) {
858		*pnum_bytes = num_bytes;
859	}
860	if (pbytes != NULL) {
861		*pbytes = (uint8_t *)state->inbuf + bytes_offset + 2;
862	}
863
864	return NT_STATUS_OK;
865}
866
867size_t cli_smb_wct_ofs(struct tevent_req **reqs, int num_reqs)
868{
869	size_t wct_ofs;
870	int i;
871
872	wct_ofs = smb_wct - 4;
873
874	for (i=0; i<num_reqs; i++) {
875		struct cli_smb_state *state;
876		state = tevent_req_data(reqs[i], struct cli_smb_state);
877		wct_ofs += iov_len(state->iov+1, state->iov_count-1);
878		wct_ofs = (wct_ofs + 3) & ~3;
879	}
880	return wct_ofs;
881}
882
883NTSTATUS cli_smb_chain_send(struct tevent_req **reqs, int num_reqs)
884{
885	struct cli_smb_state *first_state = tevent_req_data(
886		reqs[0], struct cli_smb_state);
887	struct cli_smb_state *last_state = tevent_req_data(
888		reqs[num_reqs-1], struct cli_smb_state);
889	struct cli_smb_state *state;
890	size_t wct_offset;
891	size_t chain_padding = 0;
892	int i, iovlen;
893	struct iovec *iov = NULL;
894	struct iovec *this_iov;
895	NTSTATUS status;
896
897	iovlen = 0;
898	for (i=0; i<num_reqs; i++) {
899		state = tevent_req_data(reqs[i], struct cli_smb_state);
900		iovlen += state->iov_count;
901	}
902
903	iov = talloc_array(last_state, struct iovec, iovlen);
904	if (iov == NULL) {
905		return NT_STATUS_NO_MEMORY;
906	}
907
908	first_state->chained_requests = (struct tevent_req **)talloc_memdup(
909		last_state, reqs, sizeof(*reqs) * num_reqs);
910	if (first_state->chained_requests == NULL) {
911		TALLOC_FREE(iov);
912		return NT_STATUS_NO_MEMORY;
913	}
914
915	wct_offset = smb_wct - 4;
916	this_iov = iov;
917
918	for (i=0; i<num_reqs; i++) {
919		size_t next_padding = 0;
920		uint16_t *vwv;
921
922		state = tevent_req_data(reqs[i], struct cli_smb_state);
923
924		if (i < num_reqs-1) {
925			if (!is_andx_req(CVAL(state->header, smb_com))
926			    || CVAL(state->header, smb_wct) < 2) {
927				TALLOC_FREE(iov);
928				TALLOC_FREE(first_state->chained_requests);
929				return NT_STATUS_INVALID_PARAMETER;
930			}
931		}
932
933		wct_offset += iov_len(state->iov+1, state->iov_count-1) + 1;
934		if ((wct_offset % 4) != 0) {
935			next_padding = 4 - (wct_offset % 4);
936		}
937		wct_offset += next_padding;
938		vwv = state->vwv;
939
940		if (i < num_reqs-1) {
941			struct cli_smb_state *next_state = tevent_req_data(
942				reqs[i+1], struct cli_smb_state);
943			SCVAL(vwv+0, 0, CVAL(next_state->header, smb_com));
944			SCVAL(vwv+0, 1, 0);
945			SSVAL(vwv+1, 0, wct_offset);
946		} else if (is_andx_req(CVAL(state->header, smb_com))) {
947			/* properly end the chain */
948			SCVAL(vwv+0, 0, 0xff);
949			SCVAL(vwv+0, 1, 0xff);
950			SSVAL(vwv+1, 0, 0);
951		}
952
953		if (i == 0) {
954			this_iov[0] = state->iov[0];
955		} else {
956			/*
957			 * This one is a bit subtle. We have to add
958			 * chain_padding bytes between the requests, and we
959			 * have to also include the wct field of the
960			 * subsequent requests. We use the subsequent header
961			 * for the padding, it contains the wct field in its
962			 * last byte.
963			 */
964			this_iov[0].iov_len = chain_padding+1;
965			this_iov[0].iov_base = (void *)&state->header[
966				sizeof(state->header) - this_iov[0].iov_len];
967			memset(this_iov[0].iov_base, 0, this_iov[0].iov_len-1);
968		}
969		memcpy(this_iov+1, state->iov+1,
970		       sizeof(struct iovec) * (state->iov_count-1));
971		this_iov += state->iov_count;
972		chain_padding = next_padding;
973	}
974
975	status = cli_smb_req_iov_send(reqs[0], last_state, iov, iovlen);
976	if (!NT_STATUS_IS_OK(status)) {
977		TALLOC_FREE(iov);
978		TALLOC_FREE(first_state->chained_requests);
979		return status;
980	}
981
982	return NT_STATUS_OK;
983}
984
985uint8_t *cli_smb_inbuf(struct tevent_req *req)
986{
987	struct cli_smb_state *state = tevent_req_data(
988		req, struct cli_smb_state);
989	return state->inbuf;
990}
991
992bool cli_has_async_calls(struct cli_state *cli)
993{
994	return ((tevent_queue_length(cli->outgoing) != 0)
995		|| (talloc_array_length(cli->pending) != 0));
996}
997
998struct cli_smb_oplock_break_waiter_state {
999	uint16_t fnum;
1000	uint8_t level;
1001};
1002
1003static void cli_smb_oplock_break_waiter_done(struct tevent_req *subreq);
1004
1005struct tevent_req *cli_smb_oplock_break_waiter_send(TALLOC_CTX *mem_ctx,
1006						    struct event_context *ev,
1007						    struct cli_state *cli)
1008{
1009	struct tevent_req *req, *subreq;
1010	struct cli_smb_oplock_break_waiter_state *state;
1011	struct cli_smb_state *smb_state;
1012
1013	req = tevent_req_create(mem_ctx, &state,
1014				struct cli_smb_oplock_break_waiter_state);
1015	if (req == NULL) {
1016		return NULL;
1017	}
1018
1019	/*
1020	 * Create a fake SMB request that we will never send out. This is only
1021	 * used to be set into the pending queue with the right mid.
1022	 */
1023	subreq = cli_smb_req_create(mem_ctx, ev, cli, 0, 0, 0, NULL, 0, NULL);
1024	if (tevent_req_nomem(subreq, req)) {
1025		return tevent_req_post(req, ev);
1026	}
1027	smb_state = tevent_req_data(subreq, struct cli_smb_state);
1028	SSVAL(smb_state->header, smb_mid, 0xffff);
1029
1030	if (!cli_smb_req_set_pending(subreq)) {
1031		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1032		return tevent_req_post(req, ev);
1033	}
1034	tevent_req_set_callback(subreq, cli_smb_oplock_break_waiter_done, req);
1035	return req;
1036}
1037
1038static void cli_smb_oplock_break_waiter_done(struct tevent_req *subreq)
1039{
1040	struct tevent_req *req = tevent_req_callback_data(
1041		subreq, struct tevent_req);
1042	struct cli_smb_oplock_break_waiter_state *state = tevent_req_data(
1043		req, struct cli_smb_oplock_break_waiter_state);
1044	uint8_t wct;
1045	uint16_t *vwv;
1046	uint32_t num_bytes;
1047	uint8_t *bytes;
1048	NTSTATUS status;
1049
1050	status = cli_smb_recv(subreq, 8, &wct, &vwv, &num_bytes, &bytes);
1051	if (!NT_STATUS_IS_OK(status)) {
1052		TALLOC_FREE(subreq);
1053		tevent_req_nterror(req, status);
1054		return;
1055	}
1056	state->fnum = SVAL(vwv+2, 0);
1057	state->level = CVAL(vwv+3, 1);
1058	tevent_req_done(req);
1059}
1060
1061NTSTATUS cli_smb_oplock_break_waiter_recv(struct tevent_req *req,
1062					  uint16_t *pfnum,
1063					  uint8_t *plevel)
1064{
1065	struct cli_smb_oplock_break_waiter_state *state = tevent_req_data(
1066		req, struct cli_smb_oplock_break_waiter_state);
1067	NTSTATUS status;
1068
1069	if (tevent_req_is_nterror(req, &status)) {
1070		return status;
1071	}
1072	*pfnum = state->fnum;
1073	*plevel = state->level;
1074	return NT_STATUS_OK;
1075}
1076
1077
1078struct cli_session_request_state {
1079	struct tevent_context *ev;
1080	int sock;
1081	uint32 len_hdr;
1082	struct iovec iov[3];
1083	uint8_t nb_session_response;
1084};
1085
1086static void cli_session_request_sent(struct tevent_req *subreq);
1087static void cli_session_request_recvd(struct tevent_req *subreq);
1088
1089struct tevent_req *cli_session_request_send(TALLOC_CTX *mem_ctx,
1090					    struct tevent_context *ev,
1091					    int sock,
1092					    const struct nmb_name *called,
1093					    const struct nmb_name *calling)
1094{
1095	struct tevent_req *req, *subreq;
1096	struct cli_session_request_state *state;
1097
1098	req = tevent_req_create(mem_ctx, &state,
1099				struct cli_session_request_state);
1100	if (req == NULL) {
1101		return NULL;
1102	}
1103	state->ev = ev;
1104	state->sock = sock;
1105
1106	state->iov[1].iov_base = name_mangle(
1107		state, called->name, called->name_type);
1108	if (tevent_req_nomem(state->iov[1].iov_base, req)) {
1109		return tevent_req_post(req, ev);
1110	}
1111	state->iov[1].iov_len = name_len(
1112		(unsigned char *)state->iov[1].iov_base,
1113		talloc_get_size(state->iov[1].iov_base));
1114
1115	state->iov[2].iov_base = name_mangle(
1116		state, calling->name, calling->name_type);
1117	if (tevent_req_nomem(state->iov[2].iov_base, req)) {
1118		return tevent_req_post(req, ev);
1119	}
1120	state->iov[2].iov_len = name_len(
1121		(unsigned char *)state->iov[2].iov_base,
1122		talloc_get_size(state->iov[2].iov_base));
1123
1124	_smb_setlen(((char *)&state->len_hdr),
1125		    state->iov[1].iov_len + state->iov[2].iov_len);
1126	SCVAL((char *)&state->len_hdr, 0, 0x81);
1127
1128	state->iov[0].iov_base = &state->len_hdr;
1129	state->iov[0].iov_len = sizeof(state->len_hdr);
1130
1131	subreq = writev_send(state, ev, NULL, sock, true, state->iov, 3);
1132	if (tevent_req_nomem(subreq, req)) {
1133		return tevent_req_post(req, ev);
1134	}
1135	tevent_req_set_callback(subreq, cli_session_request_sent, req);
1136	return req;
1137}
1138
1139static void cli_session_request_sent(struct tevent_req *subreq)
1140{
1141	struct tevent_req *req = tevent_req_callback_data(
1142		subreq, struct tevent_req);
1143	struct cli_session_request_state *state = tevent_req_data(
1144		req, struct cli_session_request_state);
1145	ssize_t ret;
1146	int err;
1147
1148	ret = writev_recv(subreq, &err);
1149	TALLOC_FREE(subreq);
1150	if (ret == -1) {
1151		tevent_req_error(req, err);
1152		return;
1153	}
1154	subreq = read_smb_send(state, state->ev, state->sock);
1155	if (tevent_req_nomem(subreq, req)) {
1156		return;
1157	}
1158	tevent_req_set_callback(subreq, cli_session_request_recvd, req);
1159}
1160
1161static void cli_session_request_recvd(struct tevent_req *subreq)
1162{
1163	struct tevent_req *req = tevent_req_callback_data(
1164		subreq, struct tevent_req);
1165	struct cli_session_request_state *state = tevent_req_data(
1166		req, struct cli_session_request_state);
1167	uint8_t *buf;
1168	ssize_t ret;
1169	int err;
1170
1171	ret = read_smb_recv(subreq, talloc_tos(), &buf, &err);
1172	TALLOC_FREE(subreq);
1173
1174	if (ret < 4) {
1175		ret = -1;
1176		err = EIO;
1177	}
1178	if (ret == -1) {
1179		tevent_req_error(req, err);
1180		return;
1181	}
1182	/*
1183	 * In case of an error there is more information in the data
1184	 * portion according to RFC1002. We're not subtle enough to
1185	 * respond to the different error conditions, so drop the
1186	 * error info here.
1187	 */
1188	state->nb_session_response = CVAL(buf, 0);
1189	tevent_req_done(req);
1190}
1191
1192bool cli_session_request_recv(struct tevent_req *req, int *err, uint8_t *resp)
1193{
1194	struct cli_session_request_state *state = tevent_req_data(
1195		req, struct cli_session_request_state);
1196
1197	if (tevent_req_is_unix_error(req, err)) {
1198		return false;
1199	}
1200	*resp = state->nb_session_response;
1201	return true;
1202}
1203