1/*
2   Unix SMB/CIFS implementation.
3   process incoming packets - main loop
4   Copyright (C) Andrew Tridgell 1992-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 2 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, write to the Free Software
18   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#include "includes.h"
22
23struct timeval smb_last_time;
24
25static char *InBuffer = NULL;
26char *OutBuffer = NULL;
27char *last_inbuf = NULL;
28
29/*
30 * Size of data we can send to client. Set
31 *  by the client for all protocols above CORE.
32 *  Set by us for CORE protocol.
33 */
34int max_send = BUFFER_SIZE;
35/*
36 * Size of the data we can receive. Set by us.
37 * Can be modified by the max xmit parameter.
38 */
39int max_recv = BUFFER_SIZE;
40
41extern int last_message;
42extern int global_oplock_break;
43extern userdom_struct current_user_info;
44extern int smb_read_error;
45SIG_ATOMIC_T reload_after_sighup = 0;
46SIG_ATOMIC_T got_sig_term = 0;
47BOOL global_machine_password_needs_changing = False;
48extern int max_send;
49
50/****************************************************************************
51 Function to return the current request mid from Inbuffer.
52****************************************************************************/
53
54uint16 get_current_mid(void)
55{
56	return SVAL(InBuffer,smb_mid);
57}
58
59/****************************************************************************
60 structure to hold a linked list of queued messages.
61 for processing.
62****************************************************************************/
63
64static struct pending_message_list *smb_oplock_queue;
65static struct pending_message_list *smb_sharing_violation_queue;
66
67enum q_type { OPLOCK_QUEUE, SHARE_VIOLATION_QUEUE };
68
69/****************************************************************************
70 Free up a message.
71****************************************************************************/
72
73static void free_queued_message(struct pending_message_list *msg)
74{
75	data_blob_free(&msg->buf);
76	data_blob_free(&msg->private_data);
77	SAFE_FREE(msg);
78}
79
80/****************************************************************************
81 Function to push a message onto the tail of a linked list of smb messages ready
82 for processing.
83****************************************************************************/
84
85static BOOL push_queued_message(enum q_type qt, char *buf, int msg_len, struct timeval *ptv, char *private, size_t private_len)
86{
87	struct pending_message_list *tmp_msg;
88	struct pending_message_list *msg = SMB_MALLOC_P(struct pending_message_list);
89
90	if(msg == NULL) {
91		DEBUG(0,("push_message: malloc fail (1)\n"));
92		return False;
93	}
94
95	memset(msg,'\0',sizeof(*msg));
96
97	msg->buf = data_blob(buf, msg_len);
98	if(msg->buf.data == NULL) {
99		DEBUG(0,("push_message: malloc fail (2)\n"));
100		SAFE_FREE(msg);
101		return False;
102	}
103
104	if (ptv) {
105		msg->msg_time = *ptv;
106	}
107
108	if (private) {
109		msg->private_data = data_blob(private, private_len);
110		if (msg->private_data.data == NULL) {
111			DEBUG(0,("push_message: malloc fail (3)\n"));
112			data_blob_free(&msg->buf);
113			SAFE_FREE(msg);
114		}
115	}
116
117	if (qt == OPLOCK_QUEUE) {
118		DLIST_ADD_END(smb_oplock_queue, msg, tmp_msg);
119	} else {
120		DLIST_ADD_END(smb_sharing_violation_queue, msg, tmp_msg);
121	}
122
123	DEBUG(10,("push_message: pushed message length %u on queue %s\n",
124		(unsigned int)msg_len,
125		qt == OPLOCK_QUEUE ? "smb_oplock_queue" : "smb_sharing_violation_queue" ));
126
127	return True;
128}
129
130/****************************************************************************
131 Function to push an oplock smb message onto a linked list of local smb messages ready
132 for processing.
133****************************************************************************/
134
135BOOL push_oplock_pending_smb_message(char *buf, int msg_len)
136{
137	BOOL ret = push_queued_message(OPLOCK_QUEUE, buf, msg_len, NULL, NULL, 0);
138	if (ret) {
139		/* Push the MID of this packet on the signing queue. */
140		srv_defer_sign_response(SVAL(buf,smb_mid));
141	}
142	return ret;
143}
144
145/****************************************************************************
146 Function to delete a sharing violation open message by mid.
147****************************************************************************/
148
149void remove_sharing_violation_open_smb_message(uint16 mid)
150{
151	struct pending_message_list *pml;
152
153	if (!lp_defer_sharing_violations()) {
154		return;
155	}
156
157	for (pml = smb_sharing_violation_queue; pml; pml = pml->next) {
158		if (mid == SVAL(pml->buf.data,smb_mid)) {
159			DEBUG(10,("remove_sharing_violation_open_smb_message: deleting mid %u len %u\n",
160				(unsigned int)mid, (unsigned int)pml->buf.length ));
161			DLIST_REMOVE(smb_sharing_violation_queue, pml);
162			free_queued_message(pml);
163			return;
164		}
165	}
166}
167
168/****************************************************************************
169 Move a sharing violation open retry message to the front of the list and
170 schedule it for immediate processing.
171****************************************************************************/
172
173void schedule_sharing_violation_open_smb_message(uint16 mid)
174{
175	struct pending_message_list *pml;
176	int i = 0;
177
178	if (!lp_defer_sharing_violations()) {
179		return;
180	}
181
182	for (pml = smb_sharing_violation_queue; pml; pml = pml->next) {
183		uint16 msg_mid = SVAL(pml->buf.data,smb_mid);
184		DEBUG(10,("schedule_sharing_violation_open_smb_message: [%d] msg_mid = %u\n", i++,
185			(unsigned int)msg_mid ));
186		if (mid == msg_mid) {
187			DEBUG(10,("schedule_sharing_violation_open_smb_message: scheduling mid %u\n",
188				mid ));
189			pml->msg_time.tv_sec = 0;
190			pml->msg_time.tv_usec = 0;
191			DLIST_PROMOTE(smb_sharing_violation_queue, pml);
192			return;
193		}
194	}
195
196	DEBUG(10,("schedule_sharing_violation_open_smb_message: failed to find message mid %u\n",
197		mid ));
198}
199
200/****************************************************************************
201 Return true if this mid is on the deferred queue.
202****************************************************************************/
203
204BOOL open_was_deferred(uint16 mid)
205{
206	struct pending_message_list *pml;
207
208	if (!lp_defer_sharing_violations()) {
209		return False;
210	}
211
212	for (pml = smb_sharing_violation_queue; pml; pml = pml->next) {
213		if (SVAL(pml->buf.data,smb_mid) == mid) {
214			return True;
215		}
216	}
217	return False;
218}
219
220/****************************************************************************
221 Return the message queued by this mid.
222****************************************************************************/
223
224struct pending_message_list *get_open_deferred_message(uint16 mid)
225{
226	struct pending_message_list *pml;
227
228	if (!lp_defer_sharing_violations()) {
229		return NULL;
230	}
231
232	for (pml = smb_sharing_violation_queue; pml; pml = pml->next) {
233		if (SVAL(pml->buf.data,smb_mid) == mid) {
234			return pml;
235		}
236	}
237	return NULL;
238}
239
240/****************************************************************************
241 Function to push a sharing violation open smb message onto a linked list of local smb messages ready
242 for processing.
243****************************************************************************/
244
245BOOL push_sharing_violation_open_smb_message(struct timeval *ptv, char *private, size_t priv_len)
246{
247	uint16 mid = SVAL(InBuffer,smb_mid);
248	struct timeval tv;
249	SMB_BIG_INT tdif;
250
251	if (!lp_defer_sharing_violations()) {
252		return True;
253	}
254
255	tv = *ptv;
256	tdif = tv.tv_sec;
257	tdif *= 1000000;
258	tdif += tv.tv_usec;
259
260	/* Add on the timeout. */
261	tdif += SHARING_VIOLATION_USEC_WAIT;
262
263	tv.tv_sec = tdif / 1000000;
264	tv.tv_usec = tdif % 1000000;
265
266	DEBUG(10,("push_sharing_violation_open_smb_message: pushing message len %u mid %u\
267 timeout time [%u.%06u]\n", (unsigned int) smb_len(InBuffer)+4, (unsigned int)mid,
268		(unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec));
269
270	return push_queued_message(SHARE_VIOLATION_QUEUE, InBuffer,
271			smb_len(InBuffer)+4, &tv, private, priv_len);
272}
273
274/****************************************************************************
275 Do all async processing in here. This includes UDB oplock messages, kernel
276 oplock messages, change notify events etc.
277****************************************************************************/
278
279static void async_processing(char *buffer, int buffer_len)
280{
281	DEBUG(10,("async_processing: Doing async processing.\n"));
282
283	/* check for oplock messages (both UDP and kernel) */
284	if (receive_local_message(buffer, buffer_len, 1)) {
285		process_local_message(buffer, buffer_len);
286	}
287
288	if (got_sig_term) {
289		exit_server("Caught TERM signal");
290	}
291
292	/* check for async change notify events */
293	process_pending_change_notify_queue(0);
294
295	/* check for sighup processing */
296	if (reload_after_sighup) {
297		change_to_root_user();
298		DEBUG(1,("Reloading services after SIGHUP\n"));
299		reload_services(False);
300		reload_after_sighup = 0;
301	}
302}
303
304/****************************************************************************
305  Do a select on an two fd's - with timeout.
306
307  If a local udp message has been pushed onto the
308  queue (this can only happen during oplock break
309  processing) call async_processing()
310
311  If a pending smb message has been pushed onto the
312  queue (this can only happen during oplock break
313  processing) return this next.
314
315  If the first smbfd is ready then read an smb from it.
316  if the second (loopback UDP) fd is ready then read a message
317  from it and setup the buffer header to identify the length
318  and from address.
319  Returns False on timeout or error.
320  Else returns True.
321
322The timeout is in milliseconds
323****************************************************************************/
324
325static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
326{
327	fd_set fds;
328	int selrtn;
329	struct timeval to;
330	struct timeval *pto;
331	int maxfd;
332
333	smb_read_error = 0;
334
335 again:
336
337	to.tv_sec = timeout / 1000;
338	to.tv_usec = (timeout % 1000) * 1000;
339	pto = timeout > 0 ? &to : NULL;
340
341	/*
342	 * Note that this call must be before processing any SMB
343	 * messages as we need to synchronously process any messages
344	 * we may have sent to ourselves from the previous SMB.
345	 */
346	message_dispatch();
347
348	/*
349	 * Check to see if we already have a message on the smb queue.
350	 * If so - copy and return it.
351	 */
352  	if(smb_oplock_queue != NULL) {
353		struct pending_message_list *msg = smb_oplock_queue;
354		memcpy(buffer, msg->buf.data, MIN(buffer_len, msg->buf.length));
355
356		/* Free the message we just copied. */
357		DLIST_REMOVE(smb_oplock_queue, msg);
358		free_queued_message(msg);
359
360		DEBUG(5,("receive_message_or_smb: returning queued smb message.\n"));
361		return True;
362	}
363
364	/*
365	 * Check to see if we already have a message on the deferred open queue
366	 * and it's time to schedule.
367	 */
368  	if(smb_sharing_violation_queue != NULL) {
369		BOOL pop_message = False;
370		struct pending_message_list *msg = smb_sharing_violation_queue;
371
372		if (msg->msg_time.tv_sec == 0 && msg->msg_time.tv_usec == 0) {
373			pop_message = True;
374		} else {
375			struct timeval tv;
376			SMB_BIG_INT tdif;
377
378			GetTimeOfDay(&tv);
379			tdif = usec_time_diff(&msg->msg_time, &tv);
380			if (tdif <= 0) {
381				/* Timed out. Schedule...*/
382				pop_message = True;
383				DEBUG(10,("receive_message_or_smb: queued message timed out.\n"));
384			} else {
385				/* Make a more accurate select timeout. */
386				to.tv_sec = tdif / 1000000;
387				to.tv_usec = tdif % 1000000;
388				pto = &to;
389				DEBUG(10,("receive_message_or_smb: select with timeout of [%u.%06u]\n",
390					(unsigned int)pto->tv_sec, (unsigned int)pto->tv_usec ));
391			}
392		}
393
394		if (pop_message) {
395			memcpy(buffer, msg->buf.data, MIN(buffer_len, msg->buf.length));
396
397			/* We leave this message on the queue so the open code can
398			   know this is a retry. */
399			DEBUG(5,("receive_message_or_smb: returning deferred open smb message.\n"));
400			return True;
401		}
402	}
403
404	/*
405	 * Setup the select read fd set.
406	 */
407
408	FD_ZERO(&fds);
409
410	/*
411	 * Ensure we process oplock break messages by preference.
412	 * We have to do this before the select, after the select
413	 * and if the select returns EINTR. This is due to the fact
414	 * that the selects called from async_processing can eat an EINTR
415	 * caused by a signal (we can't take the break message there).
416	 * This is hideously complex - *MUST* be simplified for 3.0 ! JRA.
417	 */
418
419	if (oplock_message_waiting(&fds)) {
420		DEBUG(10,("receive_message_or_smb: oplock_message is waiting.\n"));
421		async_processing(buffer, buffer_len);
422		/*
423		 * After async processing we must go and do the select again, as
424		 * the state of the flag in fds for the server file descriptor is
425		 * indeterminate - we may have done I/O on it in the oplock processing. JRA.
426		 */
427		goto again;
428	}
429
430	FD_SET(smbd_server_fd(),&fds);
431	maxfd = setup_oplock_select_set(&fds);
432
433	selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,NULL,NULL,pto);
434
435	/* if we get EINTR then maybe we have received an oplock
436	   signal - treat this as select returning 1. This is ugly, but
437	   is the best we can do until the oplock code knows more about
438	   signals */
439	if (selrtn == -1 && errno == EINTR) {
440		async_processing(buffer, buffer_len);
441		/*
442		 * After async processing we must go and do the select again, as
443		 * the state of the flag in fds for the server file descriptor is
444		 * indeterminate - we may have done I/O on it in the oplock processing. JRA.
445		 */
446		goto again;
447	}
448
449	/* Check if error */
450	if (selrtn == -1) {
451		/* something is wrong. Maybe the socket is dead? */
452		smb_read_error = READ_ERROR;
453		return False;
454	}
455
456	/* Did we timeout ? */
457	if (selrtn == 0) {
458		smb_read_error = READ_TIMEOUT;
459		return False;
460	}
461
462	/*
463	 * Ensure we process oplock break messages by preference.
464	 * This is IMPORTANT ! Otherwise we can starve other processes
465	 * sending us an oplock break message. JRA.
466	 */
467
468	if (oplock_message_waiting(&fds)) {
469		async_processing(buffer, buffer_len);
470		/*
471		 * After async processing we must go and do the select again, as
472		 * the state of the flag in fds for the server file descriptor is
473		 * indeterminate - we may have done I/O on it in the oplock processing. JRA.
474		 */
475		goto again;
476	}
477
478	return receive_smb(smbd_server_fd(), buffer, 0);
479}
480
481/****************************************************************************
482Get the next SMB packet, doing the local message processing automatically.
483****************************************************************************/
484
485BOOL receive_next_smb(char *inbuf, int bufsize, int timeout)
486{
487	BOOL got_keepalive;
488	BOOL ret;
489
490	do {
491		ret = receive_message_or_smb(inbuf,bufsize,timeout);
492
493		got_keepalive = (ret && (CVAL(inbuf,0) == SMBkeepalive));
494	} while (ret && got_keepalive);
495
496	return ret;
497}
498
499/****************************************************************************
500 We're terminating and have closed all our files/connections etc.
501 If there are any pending local messages we need to respond to them
502 before termination so that other smbds don't think we just died whilst
503 holding oplocks.
504****************************************************************************/
505
506void respond_to_all_remaining_local_messages(void)
507{
508	char buffer[1024];
509
510	/*
511	 * Assert we have no exclusive open oplocks.
512	 */
513
514	if(get_number_of_exclusive_open_oplocks()) {
515		DEBUG(0,("respond_to_all_remaining_local_messages: PANIC : we have %d exclusive oplocks.\n",
516			get_number_of_exclusive_open_oplocks() ));
517		return;
518	}
519
520	/*
521	 * Keep doing receive_local_message with a 1 ms timeout until
522	 * we have no more messages.
523	 */
524
525	while(receive_local_message(buffer, sizeof(buffer), 1)) {
526		/* Deal with oplock break requests from other smbd's. */
527		process_local_message(buffer, sizeof(buffer));
528	}
529
530	return;
531}
532
533
534/*
535These flags determine some of the permissions required to do an operation
536
537Note that I don't set NEED_WRITE on some write operations because they
538are used by some brain-dead clients when printing, and I don't want to
539force write permissions on print services.
540*/
541#define AS_USER (1<<0)
542#define NEED_WRITE (1<<1)
543#define TIME_INIT (1<<2)
544#define CAN_IPC (1<<3)
545#define AS_GUEST (1<<5)
546#define QUEUE_IN_OPLOCK (1<<6)
547#define DO_CHDIR (1<<7)
548
549/*
550   define a list of possible SMB messages and their corresponding
551   functions. Any message that has a NULL function is unimplemented -
552   please feel free to contribute implementations!
553*/
554static const struct smb_message_struct {
555	const char *name;
556	int (*fn)(connection_struct *conn, char *, char *, int, int);
557	int flags;
558} smb_messages[256] = {
559
560/* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
561/* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
562/* 0x02 */ { "SMBopen",reply_open,AS_USER | QUEUE_IN_OPLOCK },
563/* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
564/* 0x04 */ { "SMBclose",reply_close,AS_USER | CAN_IPC },
565/* 0x05 */ { "SMBflush",reply_flush,AS_USER},
566/* 0x06 */ { "SMBunlink",reply_unlink,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK},
567/* 0x07 */ { "SMBmv",reply_mv,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK},
568/* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
569/* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
570/* 0x0a */ { "SMBread",reply_read,AS_USER},
571/* 0x0b */ { "SMBwrite",reply_write,AS_USER | CAN_IPC },
572/* 0x0c */ { "SMBlock",reply_lock,AS_USER},
573/* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
574/* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER | QUEUE_IN_OPLOCK },
575/* 0x0f */ { "SMBmknew",reply_mknew,AS_USER},
576/* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER},
577/* 0x11 */ { "SMBexit",reply_exit,DO_CHDIR},
578/* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
579/* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
580/* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
581/* 0x15 */ { NULL, NULL, 0 },
582/* 0x16 */ { NULL, NULL, 0 },
583/* 0x17 */ { NULL, NULL, 0 },
584/* 0x18 */ { NULL, NULL, 0 },
585/* 0x19 */ { NULL, NULL, 0 },
586/* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
587/* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
588/* 0x1c */ { "SMBreadBs",NULL,0 },
589/* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
590/* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
591/* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
592/* 0x20 */ { "SMBwritec",NULL,0},
593/* 0x21 */ { NULL, NULL, 0 },
594/* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE },
595/* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER },
596/* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER },
597/* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC },
598/* 0x26 */ { "SMBtranss",NULL,AS_USER | CAN_IPC},
599/* 0x27 */ { "SMBioctl",reply_ioctl,0},
600/* 0x28 */ { "SMBioctls",NULL,AS_USER},
601/* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK },
602/* 0x2a */ { "SMBmove",NULL,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK },
603/* 0x2b */ { "SMBecho",reply_echo,0},
604/* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
605/* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER | CAN_IPC | QUEUE_IN_OPLOCK },
606/* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER | CAN_IPC },
607/* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER | CAN_IPC },
608/* 0x30 */ { NULL, NULL, 0 },
609/* 0x31 */ { NULL, NULL, 0 },
610/* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER | CAN_IPC },
611/* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER},
612/* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER},
613/* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER},
614/* 0x36 */ { NULL, NULL, 0 },
615/* 0x37 */ { NULL, NULL, 0 },
616/* 0x38 */ { NULL, NULL, 0 },
617/* 0x39 */ { NULL, NULL, 0 },
618/* 0x3a */ { NULL, NULL, 0 },
619/* 0x3b */ { NULL, NULL, 0 },
620/* 0x3c */ { NULL, NULL, 0 },
621/* 0x3d */ { NULL, NULL, 0 },
622/* 0x3e */ { NULL, NULL, 0 },
623/* 0x3f */ { NULL, NULL, 0 },
624/* 0x40 */ { NULL, NULL, 0 },
625/* 0x41 */ { NULL, NULL, 0 },
626/* 0x42 */ { NULL, NULL, 0 },
627/* 0x43 */ { NULL, NULL, 0 },
628/* 0x44 */ { NULL, NULL, 0 },
629/* 0x45 */ { NULL, NULL, 0 },
630/* 0x46 */ { NULL, NULL, 0 },
631/* 0x47 */ { NULL, NULL, 0 },
632/* 0x48 */ { NULL, NULL, 0 },
633/* 0x49 */ { NULL, NULL, 0 },
634/* 0x4a */ { NULL, NULL, 0 },
635/* 0x4b */ { NULL, NULL, 0 },
636/* 0x4c */ { NULL, NULL, 0 },
637/* 0x4d */ { NULL, NULL, 0 },
638/* 0x4e */ { NULL, NULL, 0 },
639/* 0x4f */ { NULL, NULL, 0 },
640/* 0x50 */ { NULL, NULL, 0 },
641/* 0x51 */ { NULL, NULL, 0 },
642/* 0x52 */ { NULL, NULL, 0 },
643/* 0x53 */ { NULL, NULL, 0 },
644/* 0x54 */ { NULL, NULL, 0 },
645/* 0x55 */ { NULL, NULL, 0 },
646/* 0x56 */ { NULL, NULL, 0 },
647/* 0x57 */ { NULL, NULL, 0 },
648/* 0x58 */ { NULL, NULL, 0 },
649/* 0x59 */ { NULL, NULL, 0 },
650/* 0x5a */ { NULL, NULL, 0 },
651/* 0x5b */ { NULL, NULL, 0 },
652/* 0x5c */ { NULL, NULL, 0 },
653/* 0x5d */ { NULL, NULL, 0 },
654/* 0x5e */ { NULL, NULL, 0 },
655/* 0x5f */ { NULL, NULL, 0 },
656/* 0x60 */ { NULL, NULL, 0 },
657/* 0x61 */ { NULL, NULL, 0 },
658/* 0x62 */ { NULL, NULL, 0 },
659/* 0x63 */ { NULL, NULL, 0 },
660/* 0x64 */ { NULL, NULL, 0 },
661/* 0x65 */ { NULL, NULL, 0 },
662/* 0x66 */ { NULL, NULL, 0 },
663/* 0x67 */ { NULL, NULL, 0 },
664/* 0x68 */ { NULL, NULL, 0 },
665/* 0x69 */ { NULL, NULL, 0 },
666/* 0x6a */ { NULL, NULL, 0 },
667/* 0x6b */ { NULL, NULL, 0 },
668/* 0x6c */ { NULL, NULL, 0 },
669/* 0x6d */ { NULL, NULL, 0 },
670/* 0x6e */ { NULL, NULL, 0 },
671/* 0x6f */ { NULL, NULL, 0 },
672/* 0x70 */ { "SMBtcon",reply_tcon,0},
673/* 0x71 */ { "SMBtdis",reply_tdis,DO_CHDIR},
674/* 0x72 */ { "SMBnegprot",reply_negprot,0},
675/* 0x73 */ { "SMBsesssetupX",reply_sesssetup_and_X,0},
676/* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
677/* 0x75 */ { "SMBtconX",reply_tcon_and_X,0},
678/* 0x76 */ { NULL, NULL, 0 },
679/* 0x77 */ { NULL, NULL, 0 },
680/* 0x78 */ { NULL, NULL, 0 },
681/* 0x79 */ { NULL, NULL, 0 },
682/* 0x7a */ { NULL, NULL, 0 },
683/* 0x7b */ { NULL, NULL, 0 },
684/* 0x7c */ { NULL, NULL, 0 },
685/* 0x7d */ { NULL, NULL, 0 },
686/* 0x7e */ { NULL, NULL, 0 },
687/* 0x7f */ { NULL, NULL, 0 },
688/* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
689/* 0x81 */ { "SMBsearch",reply_search,AS_USER},
690/* 0x82 */ { "SMBffirst",reply_search,AS_USER},
691/* 0x83 */ { "SMBfunique",reply_search,AS_USER},
692/* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
693/* 0x85 */ { NULL, NULL, 0 },
694/* 0x86 */ { NULL, NULL, 0 },
695/* 0x87 */ { NULL, NULL, 0 },
696/* 0x88 */ { NULL, NULL, 0 },
697/* 0x89 */ { NULL, NULL, 0 },
698/* 0x8a */ { NULL, NULL, 0 },
699/* 0x8b */ { NULL, NULL, 0 },
700/* 0x8c */ { NULL, NULL, 0 },
701/* 0x8d */ { NULL, NULL, 0 },
702/* 0x8e */ { NULL, NULL, 0 },
703/* 0x8f */ { NULL, NULL, 0 },
704/* 0x90 */ { NULL, NULL, 0 },
705/* 0x91 */ { NULL, NULL, 0 },
706/* 0x92 */ { NULL, NULL, 0 },
707/* 0x93 */ { NULL, NULL, 0 },
708/* 0x94 */ { NULL, NULL, 0 },
709/* 0x95 */ { NULL, NULL, 0 },
710/* 0x96 */ { NULL, NULL, 0 },
711/* 0x97 */ { NULL, NULL, 0 },
712/* 0x98 */ { NULL, NULL, 0 },
713/* 0x99 */ { NULL, NULL, 0 },
714/* 0x9a */ { NULL, NULL, 0 },
715/* 0x9b */ { NULL, NULL, 0 },
716/* 0x9c */ { NULL, NULL, 0 },
717/* 0x9d */ { NULL, NULL, 0 },
718/* 0x9e */ { NULL, NULL, 0 },
719/* 0x9f */ { NULL, NULL, 0 },
720/* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC | QUEUE_IN_OPLOCK},
721/* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER | CAN_IPC },
722/* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER | CAN_IPC | QUEUE_IN_OPLOCK },
723/* 0xa3 */ { NULL, NULL, 0 },
724/* 0xa4 */ { "SMBntcancel", reply_ntcancel, 0 },
725/* 0xa5 */ { "SMBntrename", reply_ntrename, AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK },
726/* 0xa6 */ { NULL, NULL, 0 },
727/* 0xa7 */ { NULL, NULL, 0 },
728/* 0xa8 */ { NULL, NULL, 0 },
729/* 0xa9 */ { NULL, NULL, 0 },
730/* 0xaa */ { NULL, NULL, 0 },
731/* 0xab */ { NULL, NULL, 0 },
732/* 0xac */ { NULL, NULL, 0 },
733/* 0xad */ { NULL, NULL, 0 },
734/* 0xae */ { NULL, NULL, 0 },
735/* 0xaf */ { NULL, NULL, 0 },
736/* 0xb0 */ { NULL, NULL, 0 },
737/* 0xb1 */ { NULL, NULL, 0 },
738/* 0xb2 */ { NULL, NULL, 0 },
739/* 0xb3 */ { NULL, NULL, 0 },
740/* 0xb4 */ { NULL, NULL, 0 },
741/* 0xb5 */ { NULL, NULL, 0 },
742/* 0xb6 */ { NULL, NULL, 0 },
743/* 0xb7 */ { NULL, NULL, 0 },
744/* 0xb8 */ { NULL, NULL, 0 },
745/* 0xb9 */ { NULL, NULL, 0 },
746/* 0xba */ { NULL, NULL, 0 },
747/* 0xbb */ { NULL, NULL, 0 },
748/* 0xbc */ { NULL, NULL, 0 },
749/* 0xbd */ { NULL, NULL, 0 },
750/* 0xbe */ { NULL, NULL, 0 },
751/* 0xbf */ { NULL, NULL, 0 },
752/* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER | QUEUE_IN_OPLOCK },
753/* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
754/* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
755/* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
756/* 0xc4 */ { NULL, NULL, 0 },
757/* 0xc5 */ { NULL, NULL, 0 },
758/* 0xc6 */ { NULL, NULL, 0 },
759/* 0xc7 */ { NULL, NULL, 0 },
760/* 0xc8 */ { NULL, NULL, 0 },
761/* 0xc9 */ { NULL, NULL, 0 },
762/* 0xca */ { NULL, NULL, 0 },
763/* 0xcb */ { NULL, NULL, 0 },
764/* 0xcc */ { NULL, NULL, 0 },
765/* 0xcd */ { NULL, NULL, 0 },
766/* 0xce */ { NULL, NULL, 0 },
767/* 0xcf */ { NULL, NULL, 0 },
768/* 0xd0 */ { "SMBsends",reply_sends,AS_GUEST},
769/* 0xd1 */ { "SMBsendb",NULL,AS_GUEST},
770/* 0xd2 */ { "SMBfwdname",NULL,AS_GUEST},
771/* 0xd3 */ { "SMBcancelf",NULL,AS_GUEST},
772/* 0xd4 */ { "SMBgetmac",NULL,AS_GUEST},
773/* 0xd5 */ { "SMBsendstrt",reply_sendstrt,AS_GUEST},
774/* 0xd6 */ { "SMBsendend",reply_sendend,AS_GUEST},
775/* 0xd7 */ { "SMBsendtxt",reply_sendtxt,AS_GUEST},
776/* 0xd8 */ { NULL, NULL, 0 },
777/* 0xd9 */ { NULL, NULL, 0 },
778/* 0xda */ { NULL, NULL, 0 },
779/* 0xdb */ { NULL, NULL, 0 },
780/* 0xdc */ { NULL, NULL, 0 },
781/* 0xdd */ { NULL, NULL, 0 },
782/* 0xde */ { NULL, NULL, 0 },
783/* 0xdf */ { NULL, NULL, 0 },
784/* 0xe0 */ { NULL, NULL, 0 },
785/* 0xe1 */ { NULL, NULL, 0 },
786/* 0xe2 */ { NULL, NULL, 0 },
787/* 0xe3 */ { NULL, NULL, 0 },
788/* 0xe4 */ { NULL, NULL, 0 },
789/* 0xe5 */ { NULL, NULL, 0 },
790/* 0xe6 */ { NULL, NULL, 0 },
791/* 0xe7 */ { NULL, NULL, 0 },
792/* 0xe8 */ { NULL, NULL, 0 },
793/* 0xe9 */ { NULL, NULL, 0 },
794/* 0xea */ { NULL, NULL, 0 },
795/* 0xeb */ { NULL, NULL, 0 },
796/* 0xec */ { NULL, NULL, 0 },
797/* 0xed */ { NULL, NULL, 0 },
798/* 0xee */ { NULL, NULL, 0 },
799/* 0xef */ { NULL, NULL, 0 },
800/* 0xf0 */ { NULL, NULL, 0 },
801/* 0xf1 */ { NULL, NULL, 0 },
802/* 0xf2 */ { NULL, NULL, 0 },
803/* 0xf3 */ { NULL, NULL, 0 },
804/* 0xf4 */ { NULL, NULL, 0 },
805/* 0xf5 */ { NULL, NULL, 0 },
806/* 0xf6 */ { NULL, NULL, 0 },
807/* 0xf7 */ { NULL, NULL, 0 },
808/* 0xf8 */ { NULL, NULL, 0 },
809/* 0xf9 */ { NULL, NULL, 0 },
810/* 0xfa */ { NULL, NULL, 0 },
811/* 0xfb */ { NULL, NULL, 0 },
812/* 0xfc */ { NULL, NULL, 0 },
813/* 0xfd */ { NULL, NULL, 0 },
814/* 0xfe */ { NULL, NULL, 0 },
815/* 0xff */ { NULL, NULL, 0 }
816
817};
818
819/*******************************************************************
820 Dump a packet to a file.
821********************************************************************/
822
823static void smb_dump(const char *name, int type, char *data, ssize_t len)
824{
825	int fd, i;
826	pstring fname;
827	if (DEBUGLEVEL < 50) return;
828
829	if (len < 4) len = smb_len(data)+4;
830	for (i=1;i<100;i++) {
831		slprintf(fname,sizeof(fname)-1, "/tmp/%s.%d.%s", name, i,
832				type ? "req" : "resp");
833		fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
834		if (fd != -1 || errno != EEXIST) break;
835	}
836	if (fd != -1) {
837		ssize_t ret = write(fd, data, len);
838		if (ret != len)
839			DEBUG(0,("smb_dump: problem: write returned %d\n", (int)ret ));
840		close(fd);
841		DEBUG(0,("created %s len %lu\n", fname, (unsigned long)len));
842	}
843}
844
845
846/****************************************************************************
847 Do a switch on the message type, and return the response size
848****************************************************************************/
849
850static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize)
851{
852	static pid_t pid= (pid_t)-1;
853	int outsize = 0;
854	extern uint16 global_smbpid;
855
856	type &= 0xff;
857
858	if (pid == (pid_t)-1)
859		pid = sys_getpid();
860
861	errno = 0;
862	last_message = type;
863
864	/* Make sure this is an SMB packet. smb_size contains NetBIOS header so subtract 4 from it. */
865	if ((strncmp(smb_base(inbuf),"\377SMB",4) != 0) || (size < (smb_size - 4))) {
866		DEBUG(2,("Non-SMB packet of length %d. Terminating server\n",smb_len(inbuf)));
867		exit_server("Non-SMB packet");
868		return(-1);
869	}
870
871	/* yuck! this is an interim measure before we get rid of our
872		current inbuf/outbuf system */
873	global_smbpid = SVAL(inbuf,smb_pid);
874
875	if (smb_messages[type].fn == NULL) {
876		DEBUG(0,("Unknown message type %d!\n",type));
877		smb_dump("Unknown", 1, inbuf, size);
878		outsize = reply_unknown(inbuf,outbuf);
879	} else {
880		int flags = smb_messages[type].flags;
881		static uint16 last_session_tag = UID_FIELD_INVALID;
882		/* In share mode security we must ignore the vuid. */
883		uint16 session_tag = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(inbuf,smb_uid);
884		connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
885
886		DEBUG(3,("switch message %s (pid %d) conn 0x%x\n",smb_fn_name(type),(int)pid,(unsigned int)conn));
887
888		smb_dump(smb_fn_name(type), 1, inbuf, size);
889		if(global_oplock_break) {
890			if(flags & QUEUE_IN_OPLOCK) {
891				/*
892				 * Queue this message as we are the process of an oplock break.
893				 */
894
895				DEBUG( 2, ( "switch_message: queueing message due to being in " ) );
896				DEBUGADD( 2, ( "oplock break state.\n" ) );
897
898				push_oplock_pending_smb_message( inbuf, size );
899				return -1;
900			}
901		}
902
903		/* Ensure this value is replaced in the incoming packet. */
904		SSVAL(inbuf,smb_uid,session_tag);
905
906		/*
907		 * Ensure the correct username is in current_user_info.
908		 * This is a really ugly bugfix for problems with
909		 * multiple session_setup_and_X's being done and
910		 * allowing %U and %G substitutions to work correctly.
911		 * There is a reason this code is done here, don't
912		 * move it unless you know what you're doing... :-).
913		 * JRA.
914		 */
915
916		if (session_tag != last_session_tag) {
917			user_struct *vuser = NULL;
918
919			last_session_tag = session_tag;
920			if(session_tag != UID_FIELD_INVALID)
921				vuser = get_valid_user_struct(session_tag);
922			if(vuser != NULL)
923				set_current_user_info(&vuser->user);
924		}
925
926		/* does this protocol need to be run as root? */
927		if (!(flags & AS_USER))
928			change_to_root_user();
929
930		/* does this protocol need a valid tree connection? */
931		if ((flags & AS_USER) && !conn)
932			return ERROR_DOS(ERRSRV, ERRinvnid);
933
934
935		/* does this protocol need to be run as the connected user? */
936		if ((flags & AS_USER) && !change_to_user(conn,session_tag)) {
937			if (flags & AS_GUEST)
938				flags &= ~AS_USER;
939			else
940				return(ERROR_FORCE_DOS(ERRSRV,ERRbaduid));
941		}
942
943		/* this code is to work around a bug is MS client 3 without
944			introducing a security hole - it needs to be able to do
945			print queue checks as guest if it isn't logged in properly */
946		if (flags & AS_USER)
947			flags &= ~AS_GUEST;
948
949		/* does it need write permission? */
950		if ((flags & NEED_WRITE) && !CAN_WRITE(conn))
951			return(ERROR_DOS(ERRSRV,ERRaccess));
952
953		/* ipc services are limited */
954		if (IS_IPC(conn) && (flags & AS_USER) && !(flags & CAN_IPC))
955			return(ERROR_DOS(ERRSRV,ERRaccess));
956
957		/* load service specific parameters */
958		if (conn && !set_current_service(conn,SVAL(inbuf,smb_flg),(flags & (AS_USER|DO_CHDIR)?True:False)))
959			return(ERROR_DOS(ERRSRV,ERRaccess));
960
961		/* does this protocol need to be run as guest? */
962		if ((flags & AS_GUEST) && (!change_to_guest() ||
963				!check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1))))
964			return(ERROR_DOS(ERRSRV,ERRaccess));
965
966		last_inbuf = inbuf;
967
968		outsize = smb_messages[type].fn(conn, inbuf,outbuf,size,bufsize);
969	}
970
971	smb_dump(smb_fn_name(type), 0, outbuf, outsize);
972
973	return(outsize);
974}
975
976
977/****************************************************************************
978 Construct a reply to the incoming packet.
979****************************************************************************/
980
981static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
982{
983	int type = CVAL(inbuf,smb_com);
984	int outsize = 0;
985	int msg_type = CVAL(inbuf,0);
986
987	GetTimeOfDay(&smb_last_time);
988
989	chain_size = 0;
990	file_chain_reset();
991	reset_chain_p();
992
993	if (msg_type != 0)
994		return(reply_special(inbuf,outbuf));
995
996	construct_reply_common(inbuf, outbuf);
997
998	outsize = switch_message(type,inbuf,outbuf,size,bufsize);
999
1000	outsize += chain_size;
1001
1002	if(outsize > 4)
1003		smb_setlen(outbuf,outsize - 4);
1004	return(outsize);
1005}
1006
1007/****************************************************************************
1008 Keep track of the number of running smbd's. This functionality is used to
1009 'hard' limit Samba overhead on resource constrained systems.
1010****************************************************************************/
1011
1012static BOOL process_count_update_successful = False;
1013
1014static int32 increment_smbd_process_count(void)
1015{
1016	int32 total_smbds;
1017
1018	if (lp_max_smbd_processes()) {
1019		total_smbds = 0;
1020		if (tdb_change_int32_atomic(conn_tdb_ctx(), "INFO/total_smbds", &total_smbds, 1) == -1)
1021			return 1;
1022		process_count_update_successful = True;
1023		return total_smbds + 1;
1024	}
1025	return 1;
1026}
1027
1028void decrement_smbd_process_count(void)
1029{
1030	int32 total_smbds;
1031
1032	if (lp_max_smbd_processes() && process_count_update_successful) {
1033		total_smbds = 1;
1034		tdb_change_int32_atomic(conn_tdb_ctx(), "INFO/total_smbds", &total_smbds, -1);
1035	}
1036}
1037
1038static BOOL smbd_process_limit(void)
1039{
1040	int32  total_smbds;
1041
1042	if (lp_max_smbd_processes()) {
1043
1044		/* Always add one to the smbd process count, as exit_server() always
1045		 * subtracts one.
1046		 */
1047
1048		if (!conn_tdb_ctx()) {
1049			DEBUG(0,("smbd_process_limit: max smbd processes parameter set with status parameter not \
1050set. Ignoring max smbd restriction.\n"));
1051			return False;
1052		}
1053
1054		total_smbds = increment_smbd_process_count();
1055		return total_smbds > lp_max_smbd_processes();
1056	}
1057	else
1058		return False;
1059}
1060
1061/****************************************************************************
1062 Process an smb from the client - split out from the smbd_process() code so
1063 it can be used by the oplock break code.
1064****************************************************************************/
1065
1066void process_smb(char *inbuf, char *outbuf)
1067{
1068	static int trans_num;
1069	int msg_type = CVAL(inbuf,0);
1070	int32 len = smb_len(inbuf);
1071	int nread = len + 4;
1072
1073	DO_PROFILE_INC(smb_count);
1074
1075	if (trans_num == 0) {
1076		/* on the first packet, check the global hosts allow/ hosts
1077		deny parameters before doing any parsing of the packet
1078		passed to us by the client.  This prevents attacks on our
1079		parsing code from hosts not in the hosts allow list */
1080		if (smbd_process_limit() ||
1081				!check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1))) {
1082			/* send a negative session response "not listening on calling name" */
1083			static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
1084			DEBUG( 1, ( "Connection denied from %s\n", client_addr() ) );
1085			(void)send_smb(smbd_server_fd(),(char *)buf);
1086			exit_server("connection denied");
1087		}
1088	}
1089
1090	DEBUG( 6, ( "got message type 0x%x of len 0x%x\n", msg_type, len ) );
1091	DEBUG( 3, ( "Transaction %d of length %d\n", trans_num, nread ) );
1092
1093	if (msg_type == 0)
1094		show_msg(inbuf);
1095	else if(msg_type == SMBkeepalive)
1096		return; /* Keepalive packet. */
1097
1098	nread = construct_reply(inbuf,outbuf,nread,max_send);
1099
1100	if(nread > 0) {
1101		if (CVAL(outbuf,0) == 0)
1102			show_msg(outbuf);
1103
1104		if (nread != smb_len(outbuf) + 4) {
1105			DEBUG(0,("ERROR: Invalid message response size! %d %d\n",
1106				nread, smb_len(outbuf)));
1107		} else if (!send_smb(smbd_server_fd(),outbuf)) {
1108			exit_server("process_smb: send_smb failed.");
1109		}
1110	}
1111	trans_num++;
1112}
1113
1114/****************************************************************************
1115 Return a string containing the function name of a SMB command.
1116****************************************************************************/
1117
1118const char *smb_fn_name(int type)
1119{
1120	const char *unknown_name = "SMBunknown";
1121
1122	if (smb_messages[type].name == NULL)
1123		return(unknown_name);
1124
1125	return(smb_messages[type].name);
1126}
1127
1128/****************************************************************************
1129 Helper functions for contruct_reply.
1130****************************************************************************/
1131
1132static uint32 common_flags2 = FLAGS2_LONG_PATH_COMPONENTS|FLAGS2_32_BIT_ERROR_CODES;
1133
1134void add_to_common_flags2(uint32 v)
1135{
1136	common_flags2 |= v;
1137}
1138
1139void remove_from_common_flags2(uint32 v)
1140{
1141	common_flags2 &= ~v;
1142}
1143
1144void construct_reply_common(char *inbuf,char *outbuf)
1145{
1146	memset(outbuf,'\0',smb_size);
1147
1148	set_message(outbuf,0,0,True);
1149	SCVAL(outbuf,smb_com,CVAL(inbuf,smb_com));
1150
1151	memcpy(outbuf+4,inbuf+4,4);
1152	SCVAL(outbuf,smb_rcls,SMB_SUCCESS);
1153	SCVAL(outbuf,smb_reh,0);
1154	SCVAL(outbuf,smb_flg, FLAG_REPLY | (CVAL(inbuf,smb_flg) & FLAG_CASELESS_PATHNAMES));
1155	SSVAL(outbuf,smb_flg2,
1156		(SVAL(inbuf,smb_flg2) & FLAGS2_UNICODE_STRINGS) |
1157		common_flags2);
1158
1159	SSVAL(outbuf,smb_err,SMB_SUCCESS);
1160	SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid));
1161	SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid));
1162	SSVAL(outbuf,smb_uid,SVAL(inbuf,smb_uid));
1163	SSVAL(outbuf,smb_mid,SVAL(inbuf,smb_mid));
1164}
1165
1166/****************************************************************************
1167 Construct a chained reply and add it to the already made reply
1168****************************************************************************/
1169
1170int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
1171{
1172	static char *orig_inbuf;
1173	static char *orig_outbuf;
1174	int smb_com1, smb_com2 = CVAL(inbuf,smb_vwv0);
1175	unsigned smb_off2 = SVAL(inbuf,smb_vwv1);
1176	char *inbuf2, *outbuf2;
1177	int outsize2;
1178	char inbuf_saved[smb_wct];
1179	char outbuf_saved[smb_wct];
1180	int outsize = smb_len(outbuf) + 4;
1181
1182	/* maybe its not chained */
1183	if (smb_com2 == 0xFF) {
1184		SCVAL(outbuf,smb_vwv0,0xFF);
1185		return outsize;
1186	}
1187
1188	if (chain_size == 0) {
1189		/* this is the first part of the chain */
1190		orig_inbuf = inbuf;
1191		orig_outbuf = outbuf;
1192	}
1193
1194	/*
1195	 * The original Win95 redirector dies on a reply to
1196	 * a lockingX and read chain unless the chain reply is
1197	 * 4 byte aligned. JRA.
1198	 */
1199
1200	outsize = (outsize + 3) & ~3;
1201
1202	/* we need to tell the client where the next part of the reply will be */
1203	SSVAL(outbuf,smb_vwv1,smb_offset(outbuf+outsize,outbuf));
1204	SCVAL(outbuf,smb_vwv0,smb_com2);
1205
1206	/* remember how much the caller added to the chain, only counting stuff
1207		after the parameter words */
1208	chain_size += outsize - smb_wct;
1209
1210	/* work out pointers into the original packets. The
1211		headers on these need to be filled in */
1212	inbuf2 = orig_inbuf + smb_off2 + 4 - smb_wct;
1213	outbuf2 = orig_outbuf + SVAL(outbuf,smb_vwv1) + 4 - smb_wct;
1214
1215	/* remember the original command type */
1216	smb_com1 = CVAL(orig_inbuf,smb_com);
1217
1218	/* save the data which will be overwritten by the new headers */
1219	memcpy(inbuf_saved,inbuf2,smb_wct);
1220	memcpy(outbuf_saved,outbuf2,smb_wct);
1221
1222	/* give the new packet the same header as the last part of the SMB */
1223	memmove(inbuf2,inbuf,smb_wct);
1224
1225	/* create the in buffer */
1226	SCVAL(inbuf2,smb_com,smb_com2);
1227
1228	/* create the out buffer */
1229	construct_reply_common(inbuf2, outbuf2);
1230
1231	DEBUG(3,("Chained message\n"));
1232	show_msg(inbuf2);
1233
1234	/* process the request */
1235	outsize2 = switch_message(smb_com2,inbuf2,outbuf2,size-chain_size,
1236				bufsize-chain_size);
1237
1238	/* copy the new reply and request headers over the old ones, but
1239		preserve the smb_com field */
1240	memmove(orig_outbuf,outbuf2,smb_wct);
1241	SCVAL(orig_outbuf,smb_com,smb_com1);
1242
1243	/* restore the saved data, being careful not to overwrite any
1244		data from the reply header */
1245	memcpy(inbuf2,inbuf_saved,smb_wct);
1246
1247	{
1248		int ofs = smb_wct - PTR_DIFF(outbuf2,orig_outbuf);
1249		if (ofs < 0) ofs = 0;
1250			memmove(outbuf2+ofs,outbuf_saved+ofs,smb_wct-ofs);
1251	}
1252
1253	return outsize2;
1254}
1255
1256/****************************************************************************
1257 Setup the needed select timeout.
1258****************************************************************************/
1259
1260static int setup_select_timeout(void)
1261{
1262	int select_timeout;
1263	int t;
1264
1265	select_timeout = blocking_locks_timeout(SMBD_SELECT_TIMEOUT);
1266	select_timeout *= 1000;
1267
1268	t = change_notify_timeout();
1269	if (t != -1)
1270		select_timeout = MIN(select_timeout, t*1000);
1271
1272	if (print_notify_messages_pending())
1273		select_timeout = MIN(select_timeout, 1000);
1274
1275	return select_timeout;
1276}
1277
1278/****************************************************************************
1279 Check if services need reloading.
1280****************************************************************************/
1281
1282void check_reload(int t)
1283{
1284	static time_t last_smb_conf_reload_time = 0;
1285	static time_t last_printer_reload_time = 0;
1286	time_t printcap_cache_time = (time_t)lp_printcap_cache_time();
1287
1288	if(last_smb_conf_reload_time == 0) {
1289		last_smb_conf_reload_time = t;
1290		/* Our printing subsystem might not be ready at smbd start up.
1291		   Then no printer is available till the first printers check
1292		   is performed.  A lower initial interval circumvents this. */
1293		if ( printcap_cache_time > 60 )
1294			last_printer_reload_time = t - printcap_cache_time + 60;
1295		else
1296			last_printer_reload_time = t;
1297	}
1298
1299	if (reload_after_sighup || (t >= last_smb_conf_reload_time+SMBD_RELOAD_CHECK)) {
1300		reload_services(True);
1301		reload_after_sighup = False;
1302		last_smb_conf_reload_time = t;
1303	}
1304
1305	/* 'printcap cache time = 0' disable the feature */
1306
1307	if ( printcap_cache_time != 0 )
1308	{
1309		/* see if it's time to reload or if the clock has been set back */
1310
1311		if ( (t >= last_printer_reload_time+printcap_cache_time)
1312			|| (t-last_printer_reload_time  < 0) )
1313		{
1314			DEBUG( 3,( "Printcap cache time expired.\n"));
1315			reload_printers();
1316			last_printer_reload_time = t;
1317		}
1318	}
1319}
1320
1321/****************************************************************************
1322 Process any timeout housekeeping. Return False if the caller should exit.
1323****************************************************************************/
1324
1325static BOOL timeout_processing(int deadtime, int *select_timeout, time_t *last_timeout_processing_time)
1326{
1327	static time_t last_keepalive_sent_time = 0;
1328	static time_t last_idle_closed_check = 0;
1329	time_t t;
1330	BOOL allidle = True;
1331	extern int keepalive;
1332
1333	if (smb_read_error == READ_EOF) {
1334		DEBUG(3,("timeout_processing: End of file from client (client has disconnected).\n"));
1335		return False;
1336	}
1337
1338	if (smb_read_error == READ_ERROR) {
1339		DEBUG(3,("timeout_processing: receive_smb error (%s) Exiting\n",
1340			strerror(errno)));
1341		return False;
1342	}
1343
1344	if (smb_read_error == READ_BAD_SIG) {
1345		DEBUG(3,("timeout_processing: receive_smb error bad smb signature. Exiting\n"));
1346		return False;
1347	}
1348
1349	*last_timeout_processing_time = t = time(NULL);
1350
1351	if(last_keepalive_sent_time == 0)
1352		last_keepalive_sent_time = t;
1353
1354	if(last_idle_closed_check == 0)
1355		last_idle_closed_check = t;
1356
1357	/* become root again if waiting */
1358	change_to_root_user();
1359
1360	/* run all registered idle events */
1361	smb_run_idle_events(t);
1362
1363	/* check if we need to reload services */
1364	check_reload(t);
1365
1366	/* automatic timeout if all connections are closed */
1367	if (conn_num_open()==0 && (t - last_idle_closed_check) >= IDLE_CLOSED_TIMEOUT) {
1368		DEBUG( 2, ( "Closing idle connection\n" ) );
1369		return False;
1370	} else {
1371		last_idle_closed_check = t;
1372	}
1373
1374	if (keepalive && (t - last_keepalive_sent_time)>keepalive) {
1375		extern struct auth_context *negprot_global_auth_context;
1376		if (!send_keepalive(smbd_server_fd())) {
1377			DEBUG( 2, ( "Keepalive failed - exiting.\n" ) );
1378			return False;
1379		}
1380
1381		/* send a keepalive for a password server or the like.
1382			This is attached to the auth_info created in the
1383		negprot */
1384		if (negprot_global_auth_context && negprot_global_auth_context->challenge_set_method
1385				&& negprot_global_auth_context->challenge_set_method->send_keepalive) {
1386
1387			negprot_global_auth_context->challenge_set_method->send_keepalive
1388			(&negprot_global_auth_context->challenge_set_method->private_data);
1389		}
1390
1391		last_keepalive_sent_time = t;
1392	}
1393
1394	/* check for connection timeouts */
1395	allidle = conn_idle_all(t, deadtime);
1396
1397	if (allidle && conn_num_open()>0) {
1398		DEBUG(2,("Closing idle connection 2.\n"));
1399		return False;
1400	}
1401
1402	if(global_machine_password_needs_changing &&
1403			/* for ADS we need to do a regular ADS password change, not a domain
1404					password change */
1405			lp_security() == SEC_DOMAIN) {
1406
1407		unsigned char trust_passwd_hash[16];
1408		time_t lct;
1409
1410		/*
1411		 * We're in domain level security, and the code that
1412		 * read the machine password flagged that the machine
1413		 * password needs changing.
1414		 */
1415
1416		/*
1417		 * First, open the machine password file with an exclusive lock.
1418		 */
1419
1420		if (secrets_lock_trust_account_password(lp_workgroup(), True) == False) {
1421			DEBUG(0,("process: unable to lock the machine account password for \
1422machine %s in domain %s.\n", global_myname(), lp_workgroup() ));
1423			return True;
1424		}
1425
1426		if(!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd_hash, &lct, NULL)) {
1427			DEBUG(0,("process: unable to read the machine account password for \
1428machine %s in domain %s.\n", global_myname(), lp_workgroup()));
1429			secrets_lock_trust_account_password(lp_workgroup(), False);
1430			return True;
1431		}
1432
1433		/*
1434		 * Make sure someone else hasn't already done this.
1435		 */
1436
1437		if(t < lct + lp_machine_password_timeout()) {
1438			global_machine_password_needs_changing = False;
1439			secrets_lock_trust_account_password(lp_workgroup(), False);
1440			return True;
1441		}
1442
1443		/* always just contact the PDC here */
1444
1445		change_trust_account_password( lp_workgroup(), NULL);
1446		global_machine_password_needs_changing = False;
1447		secrets_lock_trust_account_password(lp_workgroup(), False);
1448	}
1449
1450	/*
1451	 * Check to see if we have any blocking locks
1452	 * outstanding on the queue.
1453	 */
1454	process_blocking_lock_queue(t);
1455
1456	/* update printer queue caches if necessary */
1457
1458	update_monitored_printq_cache();
1459
1460	/*
1461	 * Check to see if we have any change notifies
1462	 * outstanding on the queue.
1463	 */
1464	process_pending_change_notify_queue(t);
1465
1466	/*
1467	 * Now we are root, check if the log files need pruning.
1468	 * Force a log file check.
1469	 */
1470	force_check_log_size();
1471	check_log_size();
1472
1473	/* Send any queued printer notify message to interested smbd's. */
1474
1475	print_notify_send_messages(0);
1476
1477	/*
1478	 * Modify the select timeout depending upon
1479	 * what we have remaining in our queues.
1480	 */
1481
1482	*select_timeout = setup_select_timeout();
1483
1484	return True;
1485}
1486
1487/****************************************************************************
1488  process commands from the client
1489****************************************************************************/
1490
1491void smbd_process(void)
1492{
1493	extern int smb_echo_count;
1494	time_t last_timeout_processing_time = time(NULL);
1495	unsigned int num_smbs = 0;
1496	const size_t total_buffer_size = BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN;
1497
1498	InBuffer = (char *)SMB_MALLOC(total_buffer_size);
1499	OutBuffer = (char *)SMB_MALLOC(total_buffer_size);
1500	if ((InBuffer == NULL) || (OutBuffer == NULL))
1501		return;
1502
1503#if defined(DEVELOPER)
1504	clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, InBuffer, total_buffer_size);
1505	clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, OutBuffer, total_buffer_size);
1506#endif
1507
1508	max_recv = MIN(lp_maxxmit(),BUFFER_SIZE);
1509
1510	while (True) {
1511		int deadtime = lp_deadtime()*60;
1512		int select_timeout = setup_select_timeout();
1513		int num_echos;
1514
1515		if (deadtime <= 0)
1516			deadtime = DEFAULT_SMBD_TIMEOUT;
1517
1518		errno = 0;
1519
1520		/* free up temporary memory */
1521		lp_talloc_free();
1522		main_loop_talloc_free();
1523
1524		/* run all registered idle events */
1525		smb_run_idle_events(time(NULL));
1526
1527
1528		/* Did someone ask for immediate checks on things like blocking locks ? */
1529		if (select_timeout == 0) {
1530			if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
1531				return;
1532			num_smbs = 0; /* Reset smb counter. */
1533		}
1534
1535#if defined(DEVELOPER)
1536		clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, InBuffer, total_buffer_size);
1537#endif
1538
1539		while (!receive_message_or_smb(InBuffer,BUFFER_SIZE+LARGE_WRITEX_HDR_SIZE,select_timeout)) {
1540			if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
1541				return;
1542			num_smbs = 0; /* Reset smb counter. */
1543		}
1544
1545		/*
1546		 * Ensure we do timeout processing if the SMB we just got was
1547		 * only an echo request. This allows us to set the select
1548		 * timeout in 'receive_message_or_smb()' to any value we like
1549		 * without worrying that the client will send echo requests
1550		 * faster than the select timeout, thus starving out the
1551		 * essential processing (change notify, blocking locks) that
1552		 * the timeout code does. JRA.
1553		 */
1554		num_echos = smb_echo_count;
1555
1556		clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, OutBuffer, total_buffer_size);
1557
1558		process_smb(InBuffer, OutBuffer);
1559
1560		if (smb_echo_count != num_echos) {
1561			if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
1562				return;
1563			num_smbs = 0; /* Reset smb counter. */
1564		}
1565
1566		num_smbs++;
1567
1568		/*
1569		 * If we are getting smb requests in a constant stream
1570		 * with no echos, make sure we attempt timeout processing
1571		 * every select_timeout milliseconds - but only check for this
1572		 * every 200 smb requests.
1573		 */
1574
1575		if ((num_smbs % 200) == 0) {
1576			time_t new_check_time = time(NULL);
1577			if(new_check_time - last_timeout_processing_time >= (select_timeout/1000)) {
1578				if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
1579					return;
1580				num_smbs = 0; /* Reset smb counter. */
1581				last_timeout_processing_time = new_check_time; /* Reset time. */
1582			}
1583		}
1584
1585		/* The timeout_processing function isn't run nearly
1586		   often enough to implement 'max log size' without
1587		   overrunning the size of the file by many megabytes.
1588		   This is especially true if we are running at debug
1589		   level 10.  Checking every 50 SMBs is a nice
1590		   tradeoff of performance vs log file size overrun. */
1591
1592		if ((num_smbs % 50) == 0 && need_to_check_log_size()) {
1593			change_to_root_user();
1594			check_log_size();
1595		}
1596	}
1597}
1598