• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.5.8/source4/lib/stream/
1/*
2   Unix SMB/CIFS mplementation.
3
4   helper layer for breaking up streams into discrete requests
5
6   Copyright (C) Andrew Tridgell  2005
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 3 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
21*/
22
23#include "includes.h"
24#include "../lib/util/dlinklist.h"
25#include "lib/events/events.h"
26#include "lib/socket/socket.h"
27#include "lib/stream/packet.h"
28#include "libcli/raw/smb.h"
29
30struct packet_context {
31	packet_callback_fn_t callback;
32	packet_full_request_fn_t full_request;
33	packet_error_handler_fn_t error_handler;
34	DATA_BLOB partial;
35	uint32_t num_read;
36	uint32_t initial_read;
37	struct socket_context *sock;
38	struct tevent_context *ev;
39	size_t packet_size;
40	void *private_data;
41	struct tevent_fd *fde;
42	bool serialise;
43	int processing;
44	bool recv_disable;
45	bool nofree;
46
47	bool busy;
48	bool destructor_called;
49
50	bool unreliable_select;
51
52	struct send_element {
53		struct send_element *next, *prev;
54		DATA_BLOB blob;
55		size_t nsent;
56		packet_send_callback_fn_t send_callback;
57		void *send_callback_private;
58	} *send_queue;
59};
60
61/*
62  a destructor used when we are processing packets to prevent freeing of this
63  context while it is being used
64*/
65static int packet_destructor(struct packet_context *pc)
66{
67	if (pc->busy) {
68		pc->destructor_called = true;
69		/* now we refuse the talloc_free() request. The free will
70		   happen again in the packet_recv() code */
71		return -1;
72	}
73
74	return 0;
75}
76
77
78/*
79  initialise a packet receiver
80*/
81_PUBLIC_ struct packet_context *packet_init(TALLOC_CTX *mem_ctx)
82{
83	struct packet_context *pc = talloc_zero(mem_ctx, struct packet_context);
84	if (pc != NULL) {
85		talloc_set_destructor(pc, packet_destructor);
86	}
87	return pc;
88}
89
90
91/*
92  set the request callback, called when a full request is ready
93*/
94_PUBLIC_ void packet_set_callback(struct packet_context *pc, packet_callback_fn_t callback)
95{
96	pc->callback = callback;
97}
98
99/*
100  set the error handler
101*/
102_PUBLIC_ void packet_set_error_handler(struct packet_context *pc, packet_error_handler_fn_t handler)
103{
104	pc->error_handler = handler;
105}
106
107/*
108  set the private pointer passed to the callback functions
109*/
110_PUBLIC_ void packet_set_private(struct packet_context *pc, void *private_data)
111{
112	pc->private_data = private_data;
113}
114
115/*
116  set the full request callback. Should return as follows:
117     NT_STATUS_OK == blob is a full request.
118     STATUS_MORE_ENTRIES == blob is not complete yet
119     any error == blob is not a valid
120*/
121_PUBLIC_ void packet_set_full_request(struct packet_context *pc, packet_full_request_fn_t callback)
122{
123	pc->full_request = callback;
124}
125
126/*
127  set a socket context to use. You must set a socket_context
128*/
129_PUBLIC_ void packet_set_socket(struct packet_context *pc, struct socket_context *sock)
130{
131	pc->sock = sock;
132}
133
134/*
135  set an event context. If this is set then the code will ensure that
136  packets arrive with separate events, by creating a immediate event
137  for any secondary packets when more than one packet is read at one
138  time on a socket. This can matter for code that relies on not
139  getting more than one packet per event
140*/
141_PUBLIC_ void packet_set_event_context(struct packet_context *pc, struct tevent_context *ev)
142{
143	pc->ev = ev;
144}
145
146/*
147  tell the packet layer the fde for the socket
148*/
149_PUBLIC_ void packet_set_fde(struct packet_context *pc, struct tevent_fd *fde)
150{
151	pc->fde = fde;
152}
153
154/*
155  tell the packet layer to serialise requests, so we don't process two
156  requests at once on one connection. You must have set the
157  event_context and fde
158*/
159_PUBLIC_ void packet_set_serialise(struct packet_context *pc)
160{
161	pc->serialise = true;
162}
163
164/*
165  tell the packet layer how much to read when starting a new packet
166  this ensures it doesn't overread
167*/
168_PUBLIC_ void packet_set_initial_read(struct packet_context *pc, uint32_t initial_read)
169{
170	pc->initial_read = initial_read;
171}
172
173/*
174  tell the packet system not to steal/free blobs given to packet_send()
175*/
176_PUBLIC_ void packet_set_nofree(struct packet_context *pc)
177{
178	pc->nofree = true;
179}
180
181/*
182  tell the packet system that select/poll/epoll on the underlying
183  socket may not be a reliable way to determine if data is available
184  for receive. This happens with underlying socket systems such as the
185  one implemented on top of GNUTLS, where there may be data in
186  encryption/compression buffers that could be received by
187  socket_recv(), while there is no data waiting at the real socket
188  level as seen by select/poll/epoll. The GNUTLS library is supposed
189  to cope with this by always leaving some data sitting in the socket
190  buffer, but it does not seem to be reliable.
191 */
192_PUBLIC_ void packet_set_unreliable_select(struct packet_context *pc)
193{
194	pc->unreliable_select = true;
195}
196
197/*
198  tell the caller we have an error
199*/
200static void packet_error(struct packet_context *pc, NTSTATUS status)
201{
202	pc->sock = NULL;
203	if (pc->error_handler) {
204		pc->error_handler(pc->private_data, status);
205		return;
206	}
207	/* default error handler is to free the callers private pointer */
208	if (!NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
209		DEBUG(0,("packet_error on %s - %s\n",
210			 talloc_get_name(pc->private_data), nt_errstr(status)));
211	}
212	talloc_free(pc->private_data);
213	return;
214}
215
216
217/*
218  tell the caller we have EOF
219*/
220static void packet_eof(struct packet_context *pc)
221{
222	packet_error(pc, NT_STATUS_END_OF_FILE);
223}
224
225
226/*
227  used to put packets on event boundaries
228*/
229static void packet_next_event(struct tevent_context *ev, struct tevent_timer *te,
230			      struct timeval t, void *private_data)
231{
232	struct packet_context *pc = talloc_get_type(private_data, struct packet_context);
233	if (pc->num_read != 0 && pc->packet_size != 0 &&
234	    pc->packet_size <= pc->num_read) {
235		packet_recv(pc);
236	}
237}
238
239
240/*
241  call this when the socket becomes readable to kick off the whole
242  stream parsing process
243*/
244_PUBLIC_ void packet_recv(struct packet_context *pc)
245{
246	size_t npending;
247	NTSTATUS status;
248	size_t nread = 0;
249	DATA_BLOB blob;
250	bool recv_retry = false;
251
252	if (pc->processing) {
253		EVENT_FD_NOT_READABLE(pc->fde);
254		pc->processing++;
255		return;
256	}
257
258	if (pc->recv_disable) {
259		EVENT_FD_NOT_READABLE(pc->fde);
260		return;
261	}
262
263	if (pc->packet_size != 0 && pc->num_read >= pc->packet_size) {
264		goto next_partial;
265	}
266
267	if (pc->packet_size != 0) {
268		/* we've already worked out how long this next packet is, so skip the
269		   socket_pending() call */
270		npending = pc->packet_size - pc->num_read;
271	} else if (pc->initial_read != 0) {
272		npending = pc->initial_read - pc->num_read;
273	} else {
274		if (pc->sock) {
275			status = socket_pending(pc->sock, &npending);
276		} else {
277			status = NT_STATUS_CONNECTION_DISCONNECTED;
278		}
279		if (!NT_STATUS_IS_OK(status)) {
280			packet_error(pc, status);
281			return;
282		}
283	}
284
285	if (npending == 0) {
286		packet_eof(pc);
287		return;
288	}
289
290again:
291
292	if (npending + pc->num_read < npending) {
293		packet_error(pc, NT_STATUS_INVALID_PARAMETER);
294		return;
295	}
296
297	if (npending + pc->num_read < pc->num_read) {
298		packet_error(pc, NT_STATUS_INVALID_PARAMETER);
299		return;
300	}
301
302	/* possibly expand the partial packet buffer */
303	if (npending + pc->num_read > pc->partial.length) {
304		if (!data_blob_realloc(pc, &pc->partial, npending+pc->num_read)) {
305			packet_error(pc, NT_STATUS_NO_MEMORY);
306			return;
307		}
308	}
309
310	if (pc->partial.length < pc->num_read + npending) {
311		packet_error(pc, NT_STATUS_INVALID_PARAMETER);
312		return;
313	}
314
315	if ((uint8_t *)pc->partial.data + pc->num_read < (uint8_t *)pc->partial.data) {
316		packet_error(pc, NT_STATUS_INVALID_PARAMETER);
317		return;
318	}
319	if ((uint8_t *)pc->partial.data + pc->num_read + npending < (uint8_t *)pc->partial.data) {
320		packet_error(pc, NT_STATUS_INVALID_PARAMETER);
321		return;
322	}
323
324	status = socket_recv(pc->sock, pc->partial.data + pc->num_read,
325			     npending, &nread);
326
327	if (NT_STATUS_IS_ERR(status)) {
328		packet_error(pc, status);
329		return;
330	}
331	if (recv_retry && NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
332		nread = 0;
333		status = NT_STATUS_OK;
334	}
335	if (!NT_STATUS_IS_OK(status)) {
336		return;
337	}
338
339	if (nread == 0 && !recv_retry) {
340		packet_eof(pc);
341		return;
342	}
343
344	pc->num_read += nread;
345
346	if (pc->unreliable_select && nread != 0) {
347		recv_retry = true;
348		status = socket_pending(pc->sock, &npending);
349		if (!NT_STATUS_IS_OK(status)) {
350			packet_error(pc, status);
351			return;
352		}
353		if (npending != 0) {
354			goto again;
355		}
356	}
357
358next_partial:
359	if (pc->partial.length != pc->num_read) {
360		if (!data_blob_realloc(pc, &pc->partial, pc->num_read)) {
361			packet_error(pc, NT_STATUS_NO_MEMORY);
362			return;
363		}
364	}
365
366	/* see if its a full request */
367	blob = pc->partial;
368	blob.length = pc->num_read;
369	status = pc->full_request(pc->private_data, blob, &pc->packet_size);
370	if (NT_STATUS_IS_ERR(status)) {
371		packet_error(pc, status);
372		return;
373	}
374	if (!NT_STATUS_IS_OK(status)) {
375		return;
376	}
377
378	if (pc->packet_size > pc->num_read) {
379		/* the caller made an error */
380		DEBUG(0,("Invalid packet_size %lu greater than num_read %lu\n",
381			 (long)pc->packet_size, (long)pc->num_read));
382		packet_error(pc, NT_STATUS_INVALID_PARAMETER);
383		return;
384	}
385
386	/* it is a full request - give it to the caller */
387	blob = pc->partial;
388	blob.length = pc->num_read;
389
390	if (pc->packet_size < pc->num_read) {
391		pc->partial = data_blob_talloc(pc, blob.data + pc->packet_size,
392					       pc->num_read - pc->packet_size);
393		if (pc->partial.data == NULL) {
394			packet_error(pc, NT_STATUS_NO_MEMORY);
395			return;
396		}
397		/* Trunate the blob sent to the caller to only the packet length */
398		if (!data_blob_realloc(pc, &blob, pc->packet_size)) {
399			packet_error(pc, NT_STATUS_NO_MEMORY);
400			return;
401		}
402	} else {
403		pc->partial = data_blob(NULL, 0);
404	}
405	pc->num_read -= pc->packet_size;
406	pc->packet_size = 0;
407
408	if (pc->serialise) {
409		pc->processing = 1;
410	}
411
412	pc->busy = true;
413
414	status = pc->callback(pc->private_data, blob);
415
416	pc->busy = false;
417
418	if (pc->destructor_called) {
419		talloc_free(pc);
420		return;
421	}
422
423	if (pc->processing) {
424		if (pc->processing > 1) {
425			EVENT_FD_READABLE(pc->fde);
426		}
427		pc->processing = 0;
428	}
429
430	if (!NT_STATUS_IS_OK(status)) {
431		packet_error(pc, status);
432		return;
433	}
434
435	/* Have we consumed the whole buffer yet? */
436	if (pc->partial.length == 0) {
437		return;
438	}
439
440	/* we got multiple packets in one tcp read */
441	if (pc->ev == NULL) {
442		goto next_partial;
443	}
444
445	blob = pc->partial;
446	blob.length = pc->num_read;
447
448	status = pc->full_request(pc->private_data, blob, &pc->packet_size);
449	if (NT_STATUS_IS_ERR(status)) {
450		packet_error(pc, status);
451		return;
452	}
453
454	if (!NT_STATUS_IS_OK(status)) {
455		return;
456	}
457
458	event_add_timed(pc->ev, pc, timeval_zero(), packet_next_event, pc);
459}
460
461
462/*
463  temporarily disable receiving
464*/
465_PUBLIC_ void packet_recv_disable(struct packet_context *pc)
466{
467	EVENT_FD_NOT_READABLE(pc->fde);
468	pc->recv_disable = true;
469}
470
471/*
472  re-enable receiving
473*/
474_PUBLIC_ void packet_recv_enable(struct packet_context *pc)
475{
476	EVENT_FD_READABLE(pc->fde);
477	pc->recv_disable = false;
478	if (pc->num_read != 0 && pc->packet_size >= pc->num_read) {
479		event_add_timed(pc->ev, pc, timeval_zero(), packet_next_event, pc);
480	}
481}
482
483/*
484  trigger a run of the send queue
485*/
486_PUBLIC_ void packet_queue_run(struct packet_context *pc)
487{
488	while (pc->send_queue) {
489		struct send_element *el = pc->send_queue;
490		NTSTATUS status;
491		size_t nwritten;
492		DATA_BLOB blob = data_blob_const(el->blob.data + el->nsent,
493						 el->blob.length - el->nsent);
494
495		status = socket_send(pc->sock, &blob, &nwritten);
496
497		if (NT_STATUS_IS_ERR(status)) {
498			packet_error(pc, status);
499			return;
500		}
501		if (!NT_STATUS_IS_OK(status)) {
502			return;
503		}
504		el->nsent += nwritten;
505		if (el->nsent == el->blob.length) {
506			DLIST_REMOVE(pc->send_queue, el);
507			if (el->send_callback) {
508				pc->busy = true;
509				el->send_callback(el->send_callback_private);
510				pc->busy = false;
511				if (pc->destructor_called) {
512					talloc_free(pc);
513					return;
514				}
515			}
516			talloc_free(el);
517		}
518	}
519
520	/* we're out of requests to send, so don't wait for write
521	   events any more */
522	EVENT_FD_NOT_WRITEABLE(pc->fde);
523}
524
525/*
526  put a packet in the send queue.  When the packet is actually sent,
527  call send_callback.
528
529  Useful for operations that must occour after sending a message, such
530  as the switch to SASL encryption after as sucessful LDAP bind relpy.
531*/
532_PUBLIC_ NTSTATUS packet_send_callback(struct packet_context *pc, DATA_BLOB blob,
533				       packet_send_callback_fn_t send_callback,
534				       void *private_data)
535{
536	struct send_element *el;
537	el = talloc(pc, struct send_element);
538	NT_STATUS_HAVE_NO_MEMORY(el);
539
540	DLIST_ADD_END(pc->send_queue, el, struct send_element *);
541	el->blob = blob;
542	el->nsent = 0;
543	el->send_callback = send_callback;
544	el->send_callback_private = private_data;
545
546	/* if we aren't going to free the packet then we must reference it
547	   to ensure it doesn't disappear before going out */
548	if (pc->nofree) {
549		if (!talloc_reference(el, blob.data)) {
550			return NT_STATUS_NO_MEMORY;
551		}
552	} else {
553		talloc_steal(el, blob.data);
554	}
555
556	if (private_data && !talloc_reference(el, private_data)) {
557		return NT_STATUS_NO_MEMORY;
558	}
559
560	EVENT_FD_WRITEABLE(pc->fde);
561
562	return NT_STATUS_OK;
563}
564
565/*
566  put a packet in the send queue
567*/
568_PUBLIC_ NTSTATUS packet_send(struct packet_context *pc, DATA_BLOB blob)
569{
570	return packet_send_callback(pc, blob, NULL, NULL);
571}
572
573
574/*
575  a full request checker for NBT formatted packets (first 3 bytes are length)
576*/
577_PUBLIC_ NTSTATUS packet_full_request_nbt(void *private_data, DATA_BLOB blob, size_t *size)
578{
579	if (blob.length < 4) {
580		return STATUS_MORE_ENTRIES;
581	}
582	*size = 4 + smb_len(blob.data);
583	if (*size > blob.length) {
584		return STATUS_MORE_ENTRIES;
585	}
586	return NT_STATUS_OK;
587}
588
589
590/*
591  work out if a packet is complete for protocols that use a 32 bit network byte
592  order length
593*/
594_PUBLIC_ NTSTATUS packet_full_request_u32(void *private_data, DATA_BLOB blob, size_t *size)
595{
596	if (blob.length < 4) {
597		return STATUS_MORE_ENTRIES;
598	}
599	*size = 4 + RIVAL(blob.data, 0);
600	if (*size > blob.length) {
601		return STATUS_MORE_ENTRIES;
602	}
603	return NT_STATUS_OK;
604}
605